Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimization based on same sequence of Toffoli gates #113

Merged
merged 2 commits into from
Nov 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion include/algorithms/optimization/esop_minimization.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,6 @@ namespace minbool {

bool checkSolution(const std::vector<MinTerm>& solution, const std::unordered_set<std::uint64_t>& onValues, const std::size_t& n);

syrec::TruthTable::Cube::Vector minimizeBoolean(syrec::TruthTable::Cube::Vector const& sigVec);
syrec::TruthTable::Cube::Set minimizeBoolean(syrec::TruthTable::Cube::Set const& sigVec);

} // namespace minbool
16 changes: 9 additions & 7 deletions include/algorithms/synthesis/dd_synthesis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,26 @@ namespace syrec {
std::size_t numGates = 0U;
qc::QuantumComputation qc;

auto pathFromSrcDst(dd::mEdge const& src, dd::mNode* const& dst, TruthTable::Cube::Vector& sigVec) const -> void;
auto pathFromSrcDst(dd::mEdge const& src, dd::mNode* const& dst, TruthTable::Cube::Vector& sigVec, TruthTable::Cube& cube) const -> void;
auto pathFromSrcDst(dd::mEdge const& src, dd::mNode* const& dst, TruthTable::Cube::Set& sigVec) const -> void;
auto pathFromSrcDst(dd::mEdge const& src, dd::mNode* const& dst, TruthTable::Cube::Set& sigVec, TruthTable::Cube& cube) const -> void;

auto pathSignature(dd::mEdge const& src, TruthTable::Cube::Vector& sigVec) const -> void;
auto pathSignature(dd::mEdge const& src, TruthTable::Cube::Vector& sigVec, TruthTable::Cube& cube) const -> void;
[[nodiscard]] auto finalSrcPathSignature(dd::mEdge const& src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) const -> TruthTable::Cube::Set;

auto pathSignature(dd::mEdge const& src, TruthTable::Cube::Set& sigVec) const -> void;
auto pathSignature(dd::mEdge const& src, TruthTable::Cube::Set& sigVec, TruthTable::Cube& cube) const -> void;

auto applyOperation(dd::QubitCount const& totalBits, dd::Qubit const& targetBit, dd::mEdge& to, dd::Controls const& ctrl, std::unique_ptr<dd::Package<>>& dd) -> void;

static auto controlRoot(dd::mEdge const& current, dd::Controls& ctrl, TruthTable::Cube const& ctrlCube) -> void;
static auto controlNonRoot(dd::mEdge const& current, dd::Controls& ctrl, TruthTable::Cube const& ctrlCube) -> void;

auto swapPaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Vector const& p1SigVec, TruthTable::Cube::Vector const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge;
auto swapPaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge;

auto shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Vector const& p1SigVec, TruthTable::Cube::Vector const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge;
auto shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge;

static auto terminate(dd::mEdge const& current) -> bool;

auto unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Vector const& p1SigVec, TruthTable::Cube::Vector const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge;
auto unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge;

auto shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge;
};
Expand Down
5 changes: 3 additions & 2 deletions include/core/truthTable/truth_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace syrec {
public:
using Value = std::optional<bool>;
using Vector = std::vector<Cube>;
using Set = std::set<Cube>;

private:
std::vector<Value> cube{};
Expand Down Expand Up @@ -55,12 +56,12 @@ namespace syrec {
}
}

static auto findMissingCube(TruthTable::Cube::Vector const& p1SigVec) -> Cube {
static auto findMissingCube(TruthTable::Cube::Set const& p1SigVec) -> Cube {
if (p1SigVec.empty()) {
return {};
}

const auto bitwidth = p1SigVec[0].size();
const auto bitwidth = p1SigVec.begin()->size();
std::uint64_t idx = 0U;
while (true) {
if (auto cube = Cube::fromInteger(idx, bitwidth); std::find(p1SigVec.begin(), p1SigVec.end(), cube) == p1SigVec.end()) {
Expand Down
9 changes: 4 additions & 5 deletions src/algorithms/optimization/esop_minimization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ namespace minbool {
return onValues.count(0) != 0U || !evalBoolean(solution, 0U, n);
}

syrec::TruthTable::Cube::Vector minimizeBoolean(syrec::TruthTable::Cube::Vector const& sigVec) {
syrec::TruthTable::Cube::Set minimizeBoolean(syrec::TruthTable::Cube::Set const& sigVec) {
if (sigVec.size() <= 1U) {
return sigVec;
}
Expand All @@ -216,7 +216,7 @@ namespace minbool {
init.emplace_back(on);
}

const auto n = sigVec[0].size();
const auto n = sigVec.begin()->size();
const auto primes = primeImplicants(init, n);

PrimeChart chart(n);
Expand All @@ -233,15 +233,14 @@ namespace minbool {

assert(checkSolution(solution, onValues, n));

syrec::TruthTable::Cube::Vector finalSigVec;
finalSigVec.reserve(solution.size());
syrec::TruthTable::Cube::Set finalSigVec;

for (auto const& ctrlCube: solution) {
syrec::TruthTable::Cube c;
for (int j = static_cast<int>(n) - 1; j >= 0; --j) {
c.emplace_back(ctrlCube[j]);
}
finalSigVec.emplace_back(c);
finalSigVec.emplace(c);
}

return finalSigVec;
Expand Down
104 changes: 58 additions & 46 deletions src/algorithms/synthesis/dd_synthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ namespace syrec {

// This algorithm provides all paths with their signatures from the `src` node to the `current` node.
// Refer to the control path section of http://www.informatik.uni-bremen.de/agra/doc/konf/12aspdac_qmdd_synth_rev.pdf
auto DDSynthesizer::pathFromSrcDst(dd::mEdge const& src, dd::mNode* const& dst, TruthTable::Cube::Vector& sigVec) const -> void {
auto DDSynthesizer::pathFromSrcDst(dd::mEdge const& src, dd::mNode* const& dst, TruthTable::Cube::Set& sigVec) const -> void {
if (src.p->v <= dst->v) {
if (src.p == dst) {
sigVec.emplace_back();
sigVec.emplace();
}
return;
}
Expand All @@ -68,10 +68,10 @@ namespace syrec {
pathFromSrcDst(src, dst, sigVec, cube);
}

auto DDSynthesizer::pathFromSrcDst(dd::mEdge const& src, dd::mNode* const& dst, TruthTable::Cube::Vector& sigVec, TruthTable::Cube& cube) const -> void {
auto DDSynthesizer::pathFromSrcDst(dd::mEdge const& src, dd::mNode* const& dst, TruthTable::Cube::Set& sigVec, TruthTable::Cube& cube) const -> void {
if (src.p->v <= dst->v) {
if (src.p == dst) {
sigVec.emplace_back(cube);
sigVec.emplace(cube);
}
return;
}
Expand All @@ -85,22 +85,55 @@ namespace syrec {
cube.pop_back();
}

//please refer to the second optimization approach introduced in https://www.cda.cit.tum.de/files/eda/2017_rc_improving_qmdd_synthesis_of_reversible_circuits.pdf
auto DDSynthesizer::finalSrcPathSignature(dd::mEdge const& src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) const -> TruthTable::Cube::Set {
if (current.p->v == src.p->v || current.p->v == 0U) {
TruthTable::Cube::Set rootSigVec;
pathFromSrcDst(src, current.p, rootSigVec);
return rootSigVec;
}

TruthTable::Cube::Set rootSigVec;
pathFromSrcDst(src, current.p, rootSigVec);

const auto tables = dd->mUniqueTable.getTables();

auto const& table = tables[current.p->v];

for (auto* p: table) {
if (p != nullptr && p != current.p && p->ref > 0) {
TruthTable::Cube::Set p1Vec;
pathSignature(p->e[0], p1Vec);

TruthTable::Cube::Set p2Vec;
pathSignature(p->e[1], p2Vec);

if (p1SigVec == p1Vec && p2SigVec == p2Vec) {
TruthTable::Cube::Set rootSigVecTmp;
pathFromSrcDst(src, p, rootSigVecTmp);
rootSigVec.merge(rootSigVecTmp);
}
}
}
return rootSigVec;
}

// This algorithm provides all the paths with their signatures for the `src` node.
// Refer to signature path section of http://www.informatik.uni-bremen.de/agra/doc/konf/12aspdac_qmdd_synth_rev.pdf
auto DDSynthesizer::pathSignature(dd::mEdge const& src, TruthTable::Cube::Vector& sigVec) const -> void {
auto DDSynthesizer::pathSignature(dd::mEdge const& src, TruthTable::Cube::Set& sigVec) const -> void {
TruthTable::Cube cube{};
const auto pathLength = static_cast<std::size_t>(src.p->v + 1);
cube.reserve(pathLength);
pathSignature(src, sigVec, cube);
}

auto DDSynthesizer::pathSignature(dd::mEdge const& src, TruthTable::Cube::Vector& sigVec, TruthTable::Cube& cube) const -> void {
auto DDSynthesizer::pathSignature(dd::mEdge const& src, TruthTable::Cube::Set& sigVec, TruthTable::Cube& cube) const -> void {
const auto nEdges = src.p->e.size();
if (src.p->v == 0) {
for (auto i = 0U; i < nEdges; ++i) {
if (src.p->e.at(i) == dd::mEdge::one) {
cube.emplace_back((i == 1U || i == 3U));
sigVec.emplace_back(cube);
sigVec.emplace(cube);
cube.pop_back();
}
}
Expand Down Expand Up @@ -166,19 +199,14 @@ namespace syrec {

// This algorithm swaps the paths present in the p' edge to the n edge and vice versa.
// Refer to the P1 algorithm of http://www.informatik.uni-bremen.de/agra/doc/konf/12aspdac_qmdd_synth_rev.pdf
auto DDSynthesizer::swapPaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Vector const& p1SigVec, TruthTable::Cube::Vector const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge {
auto DDSynthesizer::swapPaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge {
if ((current.p->e[0].isZeroTerminal() && !current.p->e[1].isZeroTerminal()) || (p2SigVec.size() > p1SigVec.size())) {
TruthTable::Cube::Vector rootSigVec;
pathFromSrcDst(src, current.p, rootSigVec);
auto rootSigVec = finalSrcPathSignature(src, current, p1SigVec, p2SigVec, dd);

const auto rootSolution = minbool::minimizeBoolean(rootSigVec);

const auto nQubits = static_cast<dd::QubitCount>(src.p->v + 1);

if (rootSolution.empty()) {
applyOperation(nQubits, current.p->v, src, {}, dd);
}

for (auto const& rootVec: rootSolution) {
dd::Controls ctrlFinal;
controlRoot(current, ctrlFinal, rootVec);
Expand All @@ -190,23 +218,22 @@ namespace syrec {

// This algorithm moves the unique paths present in the p' edge to the n edge.
// Refer to the P2 algorithm of http://www.informatik.uni-bremen.de/agra/doc/konf/12aspdac_qmdd_synth_rev.pdf
auto DDSynthesizer::shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Vector const& p1SigVec, TruthTable::Cube::Vector const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge {
TruthTable::Cube::Vector uniqueCubeVec;
auto DDSynthesizer::shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge {
TruthTable::Cube::Set uniqueCubeVec;

// Collect all the unique p' paths.
for (const auto& p2Cube: p2SigVec) {
const auto it = std::find(p1SigVec.begin(), p1SigVec.end(), p2Cube);
if (it == p1SigVec.end()) {
uniqueCubeVec.emplace_back(p2Cube);
uniqueCubeVec.emplace(p2Cube);
}
}

if (uniqueCubeVec.empty()) {
return src;
}

TruthTable::Cube::Vector rootSigVec;
pathFromSrcDst(src, current.p, rootSigVec);
auto rootSigVec = finalSrcPathSignature(src, current, p1SigVec, p2SigVec, dd);

const auto rootSolution = minbool::minimizeBoolean(rootSigVec);
const auto uniSolution = minbool::minimizeBoolean(uniqueCubeVec);
Expand All @@ -216,10 +243,6 @@ namespace syrec {
dd::Controls ctrlNonRoot;
controlNonRoot(current, ctrlNonRoot, uniCube);

if (rootSolution.empty()) {
applyOperation(nQubits, current.p->v, src, ctrlNonRoot, dd);
}

for (auto const& rootVec: rootSolution) {
dd::Controls ctrlFinal = ctrlNonRoot;
controlRoot(current, ctrlFinal, rootVec);
Expand All @@ -240,28 +263,27 @@ namespace syrec {

// This algorithm modifies the non-unique paths present in the p' edge to unique paths.
// Refer to P4 algorithm of http://www.informatik.uni-bremen.de/agra/doc/konf/12aspdac_qmdd_synth_rev.pdf
auto DDSynthesizer::unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Vector const& p1SigVec, TruthTable::Cube::Vector const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge {
std::vector<std::size_t> indices;
const auto sig2Size = p2SigVec.size();
for (std::size_t index = 0; index < sig2Size; ++index) {
if (const auto it = std::find(p1SigVec.begin(), p1SigVec.end(), p2SigVec[index]); it != p1SigVec.end()) {
indices.emplace_back(index);
auto DDSynthesizer::unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge {
TruthTable::Cube repeatedCube;
for (auto const& p2Obj: p2SigVec) {
if (const auto it = std::find(p1SigVec.begin(), p1SigVec.end(), p2Obj); it != p1SigVec.end()) {
repeatedCube = p2Obj;
}
}

// return one of the missing cubes.
const auto missCube = TruthTable::Cube::findMissingCube(p1SigVec);

TruthTable::Cube ctrlVec;
ctrlVec.resize(p2SigVec[indices[0]].size());
ctrlVec.resize(repeatedCube.size());

TruthTable::Cube targetVec;
targetVec.resize(p2SigVec[indices[0]].size());
targetVec.resize(repeatedCube.size());

// accordingly store the controls and targets.
const auto sigLength = p2SigVec[indices[0]].size();
const auto sigLength = repeatedCube.size();
for (std::size_t p2Obj = 0; p2Obj < sigLength; ++p2Obj) {
if (p2SigVec[indices[0]][p2Obj] == missCube[p2Obj]) {
if (repeatedCube[p2Obj] == missCube[p2Obj]) {
ctrlVec[p2Obj] = missCube[p2Obj];
} else {
targetVec[p2Obj] = true;
Expand All @@ -271,24 +293,14 @@ namespace syrec {
dd::Controls ctrlNonRoot;
controlNonRoot(current, ctrlNonRoot, ctrlVec);

TruthTable::Cube::Vector rootSigVec;
pathFromSrcDst(src, current.p, rootSigVec);
auto rootSigVec = finalSrcPathSignature(src, current, p1SigVec, p2SigVec, dd);

const auto nQubits = static_cast<dd::QubitCount>(src.p->v + 1);

const auto rootSolution = minbool::minimizeBoolean(rootSigVec);

const auto targetSize = targetVec.size();

if (rootSolution.empty()) {
ctrlNonRoot.emplace(dd::Control{current.p->v, dd::Control::Type::pos});
for (std::size_t i = 0; i < targetSize; ++i) {
if (targetVec[i].has_value() && *(targetVec[i])) {
applyOperation(nQubits, static_cast<dd::Qubit>(static_cast<std::size_t>(current.p->v) - (i + 1U)), src, ctrlNonRoot, dd);
}
}
}

for (auto const& rootVec: rootSolution) {
dd::Controls ctrlFinal;
controlRoot(current, ctrlFinal, rootVec);
Expand All @@ -311,10 +323,10 @@ namespace syrec {
return src;
}

TruthTable::Cube::Vector p1SigVec;
TruthTable::Cube::Set p1SigVec;
pathSignature(current.p->e[0], p1SigVec);

TruthTable::Cube::Vector p2SigVec;
TruthTable::Cube::Set p2SigVec;
pathSignature(current.p->e[1], p2SigVec);

// P1 algorithm.
Expand Down