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

DD synthesis of irreversible functions (Encoded to reversible without additional line) #115

Merged
Merged
11 changes: 11 additions & 0 deletions include/algorithms/simulation/circuit_to_truthtable.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#pragma once

#include "QuantumComputation.hpp"
#include "core/truthTable/truth_table.hpp"
#include "dd/Simulation.hpp"
burgholzer marked this conversation as resolved.
Show resolved Hide resolved

namespace syrec {

auto buildTruthTable(const qc::QuantumComputation& qc, TruthTable& tt) -> void;

} // namespace syrec
2 changes: 2 additions & 0 deletions include/algorithms/synthesis/dd_synthesis.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ namespace syrec {
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;

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

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::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, std::unique_ptr<dd::Package<>>& dd) -> dd::mEdge;
Expand Down
2 changes: 1 addition & 1 deletion include/algorithms/synthesis/encoding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ namespace syrec {
data(std::move(data)), freq(freq) {}

auto operator>(const MinHeapNode& other) const -> bool {
return freq > other.freq;
return (freq > other.freq || (freq == other.freq && (data > other.data)));
}

auto traverse(TruthTable::Cube&& encodedCube, TruthTable::CubeMap& encoding) const -> void {
Expand Down
64 changes: 64 additions & 0 deletions include/core/truthTable/truth_table.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,47 @@ namespace syrec {
return result;
}

// return bool vec representation of the cube (order is b0,b1,b2......bn)
[[nodiscard]] auto toBoolVec() const -> std::vector<bool> {
assert(std::all_of(cube.cbegin(), cube.cend(), [](auto const& v) { return v.has_value(); }));
const auto nBits = size();
std::vector<bool> result(nBits);
for (std::size_t i = 0U; i < nBits; ++i) {
result[nBits - 1 - i] = *cube[i];
}
return result;
}

// return string representation of the cube
[[nodiscard]] auto toString() const -> std::string {
std::stringstream ss{};
for (const auto& i: cube) {
if (!i.has_value()) {
ss << '-';
} else {
ss << (*i ? '1' : '0');
}
}
return ss.str();
}

// checks if 2 Cubes are equal irrespective of don't care
[[nodiscard]] static auto checkCubeEquality(const Cube& c1, const Cube& c2, const bool equalityUpToDontCare = true) -> bool {
if (c1.size() != c2.size()) {
return false;
}
const auto nBits = c1.size();
for (auto i = 0U; i < nBits; ++i) {
if (equalityUpToDontCare && (!c1[i].has_value() || !c2[i].has_value())) {
continue;
}
if (*c1[i] != *c2[i]) {
return false;
}
}
return true;
}

[[nodiscard]] auto completeCubes() const -> Vector;

auto insertZero() -> void {
Expand Down Expand Up @@ -136,6 +177,10 @@ namespace syrec {
return (cube < cv.cube);
}

auto operator>(const Cube& cv) const -> bool {
return (cube > cv.cube);
}

auto operator==(const Cube& cv) const -> bool {
return (cube == cv.cube);
}
Expand Down Expand Up @@ -267,6 +312,10 @@ namespace syrec {
return cubeMap.find(Cube::fromString(str));
}

auto find(const Cube& c) -> decltype(cubeMap.cbegin()) {
return cubeMap.find(c);
}

auto try_emplace(const Cube& input, const Cube& output) -> void { // NOLINT(readability-identifier-naming) keeping same Interface as std::vector
assert(cubeMap.empty() || (input.size() == nInputs() && output.size() == nOutputs()));
cubeMap.try_emplace(input, output);
Expand All @@ -280,6 +329,21 @@ namespace syrec {
cubeMap.insert(std::move(nh));
}

static auto equal(TruthTable& tt1, TruthTable& tt2, const bool equalityUpToDontCare = true) -> bool {
if (!equalityUpToDontCare) {
return (tt1 == tt2);
}
for (auto const& [input, output]: tt1) {
if (auto it = tt2.find(input); it == tt2.end()) {
continue;
}
burgholzer marked this conversation as resolved.
Show resolved Hide resolved
if (!Cube::checkCubeEquality(tt1[input], tt2[input])) {
return false;
}
}
return true;
}

auto clear() -> void {
cubeMap.clear();
}
Expand Down
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ add_library(
${CMAKE_CURRENT_SOURCE_DIR}/algorithms/synthesis/syrec_cost_aware_synthesis.cpp
${CMAKE_CURRENT_SOURCE_DIR}/algorithms/synthesis/syrec_line_aware_synthesis.cpp
${CMAKE_CURRENT_SOURCE_DIR}/algorithms/simulation/simple_simulation.cpp
${CMAKE_CURRENT_SOURCE_DIR}/algorithms/simulation/circuit_to_truthtable.cpp
${CMAKE_CURRENT_SOURCE_DIR}/algorithms/synthesis/dd_synthesis.cpp
${CMAKE_CURRENT_SOURCE_DIR}/algorithms/synthesis/encoding.cpp
${CMAKE_CURRENT_SOURCE_DIR}/algorithms/optimization/esop_minimization.cpp
${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/optimization/esop_minimization.hpp
${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/simulation/simple_simulation.hpp
${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/simulation/circuit_to_truthtable.hpp
${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/synthesis/syrec_synthesis.hpp
${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/synthesis/syrec_cost_aware_synthesis.hpp
${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/synthesis/syrec_line_aware_synthesis.hpp
Expand Down
25 changes: 25 additions & 0 deletions src/algorithms/simulation/circuit_to_truthtable.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "algorithms/simulation/circuit_to_truthtable.hpp"

namespace syrec {

auto buildTruthTable(const qc::QuantumComputation& qc, TruthTable& tt) -> void {
const auto nBits = qc.getNqubits();
auto dd = std::make_unique<dd::Package<>>(nBits);

const auto totalInputs = 1U << nBits;

std::uint64_t n = 0U;

while (n < totalInputs) {
const auto inCube = TruthTable::Cube::fromInteger(n, nBits);

auto const inEdge = dd->makeBasisState(nBits, inCube.toBoolVec());
const auto out = dd::simulate(&qc, inEdge, dd, 1);
const auto outString = out.begin()->first;

burgholzer marked this conversation as resolved.
Show resolved Hide resolved
tt.try_emplace(inCube, TruthTable::Cube::fromString(outString));
++n;
}
}

} // namespace syrec
1 change: 0 additions & 1 deletion src/algorithms/simulation/simple_simulation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,4 @@ namespace syrec {
t.stop();
}
}

} // namespace syrec
56 changes: 41 additions & 15 deletions src/algorithms/synthesis/dd_synthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,18 @@ namespace syrec {
for (const auto& [input, output]: tt) {
// truth table has to be completely specified
assert(input[0].has_value());
assert(output[0].has_value());
const auto in = *input[0];
const auto out = *output[0];
const auto index = (static_cast<std::size_t>(out) * 2U) + static_cast<std::size_t>(in);
edges.at(index) = dd::mEdge::one;

const auto in = *input[0];
const auto out = *output[0];

if (output[0].has_value()) {
const auto index = (static_cast<std::size_t>(out) * 2U) + static_cast<std::size_t>(in);
edges.at(index) = dd::mEdge::one;
} else {
const auto offset = in ? 1U : 0U;
edges.at(0U + offset) = dd::mEdge::one;
edges.at(2U + offset) = dd::mEdge::one;
}
}
return dd->makeDDNode(0, edges);
}
Expand All @@ -33,15 +40,22 @@ namespace syrec {
for (const auto& [input, output]: tt) {
// truth table has to be completely specified
assert(input[0].has_value());
assert(output[0].has_value());
const auto in = *input[0];
const auto out = *output[0];
const auto index = static_cast<std::size_t>(out) * 2U + static_cast<std::size_t>(in);

const auto in = *input[0];
const auto out = *output[0];

TruthTable::Cube reducedInput(input.begin() + 1, input.end());
TruthTable::Cube reducedOutput(output.begin() + 1, output.end());
subTables.at(index).try_emplace(std::move(reducedInput), std::move(reducedOutput));
}

if (output[0].has_value()) {
const auto index = static_cast<std::size_t>(out) * 2U + static_cast<std::size_t>(in);
subTables.at(index).try_emplace(std::move(reducedInput), std::move(reducedOutput));
} else {
const auto offset = in ? 1U : 0U;
subTables.at(0 + offset).try_emplace(reducedInput, reducedOutput);
subTables.at(2 + offset).try_emplace(reducedInput, reducedOutput);
}
}
// recursively build the DD for each sub-table
for (std::size_t i = 0U; i < 4U; ++i) {
edges.at(i) = buildDD(subTables.at(i), dd);
Expand Down Expand Up @@ -181,6 +195,18 @@ namespace syrec {
}
}

// Check whether all the edges of the current node are pointing to the same node (indicating a don't care node).
auto DDSynthesizer::dcNodeCondition(dd::mEdge const& current) -> bool {
if (!(dd::mNode::isTerminal(current.p))) {
if (current.p->v == 0U) {
return std::all_of(current.p->e.begin(), current.p->e.end(), [](const auto& e) { return e == dd::mEdge::one; });
}

return std::all_of(current.p->e.begin(), current.p->e.end(), [&current](const auto& e) { return e.p == current.p->e[0].p; });
}
return false;
}

// This function performs the multi-control (if any) X operation.
auto DDSynthesizer::applyOperation(dd::QubitCount const& totalBits, dd::Qubit const& targetBit, dd::mEdge& to, dd::Controls const& ctrl, std::unique_ptr<dd::Package<>>& dd) -> void {
// create operation and corresponding decision diagram
Expand Down Expand Up @@ -354,7 +380,7 @@ namespace syrec {
runtime = 0.;
numGates = 0U;

if (src.p == nullptr || src.p->isIdentity()) {
if (src.p == nullptr || src.p->isIdentity() || dcNodeCondition(src)) {
return qc;
}

Expand All @@ -380,7 +406,7 @@ namespace syrec {
const auto current = queue.front();
queue.pop();

if (current.p == nullptr || current.p->isIdentity()) {
if (current.p == nullptr || current.p->isIdentity() || dcNodeCondition(current)) {
continue;
}

Expand All @@ -400,7 +426,7 @@ namespace syrec {

if (pathsShifted) {
// stopping criterion
if (srcShifted.p->isIdentity()) {
if (srcShifted.p->isIdentity() && dcNodeCondition(srcShifted)) {
break;
}

Expand All @@ -414,7 +440,7 @@ namespace syrec {

// if all paths have been shifted, the children of the current node need to be processed.
for (const auto& e: current.p->e) {
if (!e.isTerminal() && visited.find(e) == visited.end()) {
if (!e.isTerminal() && !dcNodeCondition(e) && visited.find(e) == visited.end()) {
queue.emplace(e);
visited.emplace(e);
}
Expand Down
3 changes: 0 additions & 3 deletions src/algorithms/synthesis/encoding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ namespace syrec {
TruthTable newTT{};

for (auto const& [input, output]: tt) {
// ensure that all outputs are complete
assert(std::none_of(output.cbegin(), output.cend(), [](auto const& v) { return !v.has_value(); }));

// compute the complete cubes for the input
auto completeInputs = input.completeCubes();
// move all the complete cubes to the new cube map
Expand Down
3 changes: 2 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,8 @@ package_add_test(
unittests/test_extend_tt.cpp
unittests/test_huffman.cpp
unittests/test_pla_parser.cpp
unittests/test_dd_synthesis.cpp)
unittests/test_dd_synthesis.cpp
unittests/test_dd_synthesis_dc.cpp)

add_custom_command(
TARGET ${PROJECT_NAME}_test
Expand Down
9 changes: 9 additions & 0 deletions test/circuits/dc3bit.pla
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.i 3
.o 3
00- 0--
01- 10-
100 111
101 0--
110 0--
111 110
.e
11 changes: 11 additions & 0 deletions test/circuits/dc3bitNew.pla
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
.i 3
.o 3
000 0--
001 10-
010 0--
011 110
100 10-
101 111
110 0--
111 0--
.e
5 changes: 5 additions & 0 deletions test/circuits/dcX2bit.pla
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.i 2
.o 2
0- 1-
1- 0-
.e
7 changes: 7 additions & 0 deletions test/circuits/dcX4bit.pla
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.i 4
.o 4
00-- 11--
01-- 10--
10-- 01--
11-- 00--
.e
36 changes: 36 additions & 0 deletions test/circuits/sym6_32.pla
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Function: sym6_32
# This file has been taken from RevLib (www.revlib.org).
.i 6
.o 1
000011 1
000101 1
000110 1
000111 1
001001 1
001010 1
001011 1
001100 1
001101 1
001110 1
001111 1
010001 1
010010 1
010011 1
010100 1
010101 1
010110 1
010111 1
011000 1
011001 1
011010 1
011011 1
011100 1
011101 1
011110 1
100001 1
100010 1
100011 1
100100 1
100101 1
100110 1
100111 1
Loading