From fbad786b01b7b5580b28b5c5c2e5abc2a1e8d161 Mon Sep 17 00:00:00 2001 From: SmaranTum Date: Sun, 4 Dec 2022 12:21:49 +0100 Subject: [PATCH 1/6] Decoder functionality included. Accordingly the signatures of certain functions are changed. --- include/algorithms/synthesis/dd_synthesis.hpp | 5 +- include/algorithms/synthesis/encoding.hpp | 4 +- src/algorithms/synthesis/dd_synthesis.cpp | 128 ++++++++++++++---- src/algorithms/synthesis/encoding.cpp | 44 +++++- test/unittests/test_dd_synthesis.cpp | 2 +- test/unittests/test_dd_synthesis_dc.cpp | 57 +++++--- test/unittests/test_huffman.cpp | 8 +- 7 files changed, 191 insertions(+), 57 deletions(-) diff --git a/include/algorithms/synthesis/dd_synthesis.hpp b/include/algorithms/synthesis/dd_synthesis.hpp index 76887f8c..eff5b852 100644 --- a/include/algorithms/synthesis/dd_synthesis.hpp +++ b/include/algorithms/synthesis/dd_synthesis.hpp @@ -17,7 +17,7 @@ namespace syrec { explicit DDSynthesizer(const std::size_t nqubits): qc(nqubits) {} - auto synthesize(dd::mEdge src, std::unique_ptr>& dd) -> qc::QuantumComputation&; + auto synthesize(dd::mEdge src, TruthTable::CubeMap const& codeword, std::size_t const& r, std::size_t const& m, std::unique_ptr>& dd) -> qc::QuantumComputation&; [[nodiscard]] auto numGate() const -> std::size_t { return numGates; @@ -56,6 +56,9 @@ namespace syrec { auto unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& dd) -> dd::mEdge; auto shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd) -> dd::mEdge; + + auto decoder(TruthTable::CubeMap const& codeword, std::size_t const& r, std::size_t const& m, std::unique_ptr>& dd) -> void; + auto synthesizeDD(dd::mEdge src, std::unique_ptr>& dd, std::size_t const& m, bool flag) -> void; }; } // namespace syrec diff --git a/include/algorithms/synthesis/encoding.hpp b/include/algorithms/synthesis/encoding.hpp index eb692a39..d46a50cf 100644 --- a/include/algorithms/synthesis/encoding.hpp +++ b/include/algorithms/synthesis/encoding.hpp @@ -38,8 +38,8 @@ namespace syrec { auto extend(TruthTable& tt) -> void; - auto encodeHuffman(TruthTable& tt) -> void; + auto encodeHuffman(TruthTable& tt) -> std::tuple; - auto augmentWithConstants(TruthTable& tt) -> void; + auto augmentWithConstants(TruthTable& tt, std::size_t const& nBits) -> void; } //namespace syrec diff --git a/src/algorithms/synthesis/dd_synthesis.cpp b/src/algorithms/synthesis/dd_synthesis.cpp index 27193d18..f1719f35 100644 --- a/src/algorithms/synthesis/dd_synthesis.cpp +++ b/src/algorithms/synthesis/dd_synthesis.cpp @@ -183,12 +183,9 @@ namespace syrec { const auto cubeSize = ctrlCube.size(); for (auto i = 0U; i < cubeSize; ++i) { if (ctrlCube[i].has_value()) { - const auto idx = static_cast(static_cast(current.p->v) - i - 1U); - if (*ctrlCube[i]) { - ctrl.emplace(dd::Control{idx, dd::Control::Type::pos}); - } else { - ctrl.emplace(dd::Control{idx, dd::Control::Type::neg}); - } + const auto idx = static_cast(static_cast(current.p->v) - i - 1U); + const auto ctrlType = *ctrlCube[i] ? dd::Control::Type::pos : dd::Control::Type::neg; + ctrl.emplace(dd::Control{idx, ctrlType}); } } } @@ -198,12 +195,9 @@ namespace syrec { const auto cubeSize = ctrlCube.size(); for (auto i = 0U; i < cubeSize; ++i) { if (ctrlCube[i].has_value()) { - const auto idx = static_cast((cubeSize - i) + static_cast(current.p->v)); - if (*ctrlCube[i]) { - ctrl.emplace(dd::Control{idx, dd::Control::Type::pos}); - } else { - ctrl.emplace(dd::Control{idx, dd::Control::Type::neg}); - } + const auto idx = static_cast((cubeSize - i) + static_cast(current.p->v)); + const auto ctrlType = *ctrlCube[i] ? dd::Control::Type::pos : dd::Control::Type::neg; + ctrl.emplace(dd::Control{idx, ctrlType}); } } } @@ -372,11 +366,10 @@ namespace syrec { for (auto const& rootVec: rootSolution) { dd::Controls ctrlFinal; controlRoot(current, ctrlFinal, rootVec); - if (!changePaths) { - ctrlFinal.emplace(dd::Control{current.p->v, dd::Control::Type::pos}); - } else { - ctrlFinal.emplace(dd::Control{current.p->v, dd::Control::Type::neg}); - } + + const auto ctrlType = changePaths ? dd::Control::Type::neg : dd::Control::Type::pos; + ctrlFinal.emplace(dd::Control{current.p->v, ctrlType}); + ctrlFinal.insert(ctrlNonRoot.begin(), ctrlNonRoot.end()); for (std::size_t i = 0; i < targetSize; ++i) { @@ -433,21 +426,83 @@ namespace syrec { return unifyPath(src, current, p1SigVec, p2SigVec, changePaths, dd); } - // This function returns the operations required to synthesize the DD. - auto DDSynthesizer::synthesize(dd::mEdge src, std::unique_ptr>& dd) -> qc::QuantumComputation& { - qc.clear(); - runtime = 0.; - numGates = 0U; + // Refer to the decoder algorithm of https://www.cda.cit.tum.de/files/eda/2018_aspdac_coding_techniques_in_synthesis.pdf. + auto DDSynthesizer::decoder(TruthTable::CubeMap const& codeword, std::size_t const& r, std::size_t const& m, std::unique_ptr>& dd) -> void { + const auto codeLength = codeword.begin()->second.size(); + const auto totalBits = qc.getNqubits(); + // if r = 0, skip to decoder part 2. + + //Decoder part 1. + if (r > 0U) { + for (const auto& [pattern, code]: codeword) { + TruthTable::Cube targetCube(pattern.begin(), pattern.begin() + static_cast(r)); + + dd::Controls ctrl; + for (auto i = 0U; i < codeLength; i++) { + if (code[i].has_value()) { + const auto ctrlType = *code[i] ? dd::Control::Type::pos : dd::Control::Type::neg; + ctrl.emplace(dd::Control{static_cast((codeLength - 1U) - i), ctrlType}); + } + } + + const auto targetSize = targetCube.size(); + + for (std::size_t i = 0U; i < targetSize; ++i) { + if (targetCube[i].has_value() && *(targetCube[i])) { + auto op = std::make_unique(totalBits, ctrl, static_cast((static_cast(totalBits) - 1U) - i), qc::X); + qc.emplace_back(op); + ++numGates; + } + } + } + } + + //Decoder part 2. + const auto correctionBits = m - r; + + if (correctionBits == 0U) { + return; + } + + TruthTable ttCorrection{}; + + for (const auto& [pattern, code]: codeword) { + TruthTable::Cube outCube(pattern); + outCube.resize(totalBits); + TruthTable::Cube inCube(pattern.begin(), pattern.begin() + static_cast(r)); + for (auto i = 0U; i < codeLength; i++) { + inCube.emplace_back(code[i]); + } + ttCorrection.try_emplace(inCube, outCube); + } + + // Extend the dc in the inputs. + TruthTable newTT{}; + for (auto const& [input, output]: ttCorrection) { + auto completeInputs = input.completeCubes(); + for (auto const& completeInput: completeInputs) { + newTT.try_emplace(completeInput, output); + } + } + const auto ttCorrectionDD = buildDD(newTT, dd); + synthesizeDD(ttCorrectionDD, dd, m, true); + } + + // This function returns the operations required to synthesize the DD. + // flag -> If true, the synthesis is stopped after the nodeThreshold is reached. + // m -> No. of primary outputs. + auto DDSynthesizer::synthesizeDD(dd::mEdge src, std::unique_ptr>& dd, std::size_t const& m, bool flag) -> void { if (src.p == nullptr || src.p->isIdentity() || dcNodeCondition(src)) { - return qc; + return; } + // The Node after which the synthesis can be terminated without affecting the functionality. + const auto nodeThreshold = static_cast(qc.getNqubits()) - static_cast(m); + // This following ensures that the `src` node resembles an identity structure. // Refer to algorithm Q of http://www.informatik.uni-bremen.de/agra/doc/konf/12aspdac_qmdd_synth_rev.pdf. - const auto start = std::chrono::steady_clock::now(); - // to preserve the `src` DD throughout the synthesis, its reference count has to be at least 2. while (src.p->ref < 2U) { dd->incRef(src); @@ -463,6 +518,12 @@ namespace syrec { // while there are nodes left to process. while (!queue.empty()) { const auto current = queue.front(); + + //The synthesis is stopped after the nodeThreshold is reached (considered only while synthesizing the decoder) + if (current.p->v == nodeThreshold - 1 && flag) { + break; + } + queue.pop(); if (current.p == nullptr || current.p->isIdentity() || dcNodeCondition(current)) { @@ -505,6 +566,23 @@ namespace syrec { } } } + } + + auto DDSynthesizer::synthesize(dd::mEdge src, TruthTable::CubeMap const& codeword, std::size_t const& r, std::size_t const& m, std::unique_ptr>& dd) -> qc::QuantumComputation& { + qc.clear(); + runtime = 0.; + numGates = 0U; + + const auto start = std::chrono::steady_clock::now(); + + synthesizeDD(src, dd, m, false); + + // if codeword is empty, then function is src edge realizes a reversible function by default. + if (!codeword.empty()) { + // synthesizing decoder circuit. + decoder(codeword, r, m, dd); + } + runtime = static_cast((std::chrono::steady_clock::now() - start).count()); return qc; diff --git a/src/algorithms/synthesis/encoding.cpp b/src/algorithms/synthesis/encoding.cpp index 7e4252bd..0463233b 100644 --- a/src/algorithms/synthesis/encoding.cpp +++ b/src/algorithms/synthesis/encoding.cpp @@ -40,7 +40,7 @@ namespace syrec { } } - auto encodeHuffman(TruthTable& tt) -> void { + auto encodeHuffman(TruthTable& tt) -> std::tuple { std::map outputFreq; for (const auto& [input, output]: tt) { outputFreq[output]++; @@ -48,7 +48,7 @@ namespace syrec { // if the truth table function is already reversible, no encoding is necessary if (outputFreq.size() == tt.size()) { - return; + return std::make_tuple(TruthTable::CubeMap{}, 0U); } // create a priority queue for building the Huffman tree @@ -60,12 +60,19 @@ namespace syrec { decltype(comp)> minHeap(comp); + std::unordered_set freqSet; + freqSet.reserve(outputFreq.size()); + // initialize the leaves of the Huffman tree from the output frequencies for (const auto& [output, freq]: outputFreq) { const auto requiredGarbage = static_cast(std::ceil(std::log2(freq))); + freqSet.emplace(requiredGarbage); minHeap.emplace(std::make_shared(output, requiredGarbage)); } + // Minimum no. of additional lines required. + const auto additionalLines = *std::max_element(freqSet.begin(), freqSet.end()); + // combine the nodes with the smallest weights until there is only one node left while (minHeap.size() > 1U) { // pop the two nodes with the smallest weights @@ -84,6 +91,9 @@ namespace syrec { } const auto requiredGarbage = minHeap.top()->freq; + const auto nBits = std::max(tt.nInputs(), tt.nOutputs() + additionalLines); + const auto r = nBits - requiredGarbage; + // determine encoding from Huffman tree TruthTable::CubeMap encoding{}; minHeap.top()->traverse({}, encoding); @@ -93,13 +103,41 @@ namespace syrec { output.resize(requiredGarbage); } + // modify the codewords by filling in the redundant dc positions. + for (auto& [pattern, code]: encoding) { + TruthTable::Cube outCube(pattern); + outCube.resize(nBits); + + TruthTable::Cube newCode{}; + newCode.reserve(requiredGarbage); + for (auto i = 0U; i < requiredGarbage; i++) { + if (code[i].has_value()) { + newCode.emplace_back(code[i]); + } else { + newCode.emplace_back(outCube[r + i]); + } + } + + encoding[pattern] = newCode; + } + // encode all the outputs for (auto& [input, output]: tt) { output = encoding[output]; } + + return std::make_tuple(encoding, additionalLines); } - auto augmentWithConstants(TruthTable& tt) -> void { + auto augmentWithConstants(TruthTable& tt, std::size_t const& nBits) -> void { + //add necessary constant inputs to the outputs based on the total number of bits (nBits) + const auto ancillaBits = nBits - tt.nOutputs(); + for (auto& [input, output]: tt) { + for (auto i = 0U; i < ancillaBits; i++) { + output.insertZero(); + } + } + for (auto const& [input, output]: tt) { const auto inputSize = input.size(); const auto outputSize = output.size(); diff --git a/test/unittests/test_dd_synthesis.cpp b/test/unittests/test_dd_synthesis.cpp index 2ce6a0ca..88193684 100644 --- a/test/unittests/test_dd_synthesis.cpp +++ b/test/unittests/test_dd_synthesis.cpp @@ -62,7 +62,7 @@ TEST_P(TestDDSynth, GenericDDSynthesisTest) { EXPECT_TRUE(ttDD.p != nullptr); DDSynthesizer synthesizer(tt.nInputs()); - const auto& qc = synthesizer.synthesize(ttDD, dd); + const auto& qc = synthesizer.synthesize(ttDD, {}, 0U, tt.nOutputs(), dd); const auto& qcDD = dd::buildFunctionality(&qc, dd); EXPECT_EQ(ttDD, qcDD); diff --git a/test/unittests/test_dd_synthesis_dc.cpp b/test/unittests/test_dd_synthesis_dc.cpp index 74b16ef6..c4ece286 100644 --- a/test/unittests/test_dd_synthesis_dc.cpp +++ b/test/unittests/test_dd_synthesis_dc.cpp @@ -11,6 +11,7 @@ using namespace syrec; class TestDDSynthDc: public testing::TestWithParam { protected: TruthTable tt{}; + TruthTable ttExpected{}; TruthTable ttqc{}; std::string testCircuitsDir = "./circuits/"; std::unique_ptr> dd = std::make_unique>(15U); @@ -38,35 +39,20 @@ INSTANTIATE_TEST_SUITE_P(TestDDSynth, TestDDSynthDc, "rd32_19", "c17", "con1", - "root", "sqr", - "sqrt8", - "life", "aludc", "minialu", - "dc2", - "dk27", - "pm1", "majority", - "max10", "4gt10", "counter", "4gt5", "4mod5", "decode24", - "mod10", - "asym", "decode24e", - "radd", - "radd8", "rd53", - "rd84", - "dist", - "mlp4", "wim", "z4", - "z4ml", - "misex"), + "z4ml"), [](const testing::TestParamInfo& info) { auto s = info.param; std::replace( s.begin(), s.end(), '-', '_'); @@ -76,20 +62,49 @@ TEST_P(TestDDSynthDc, GenericDDSynthesisDcTest) { EXPECT_TRUE(readPla(tt, fileName)); extend(tt); - encodeHuffman(tt); + TruthTable const ttOri(tt); //unchanged Truth Table. - augmentWithConstants(tt); + //n -> No. of primary inputs. + //m -> No. of primary outputs. + //k1 -> Minimum no. of additional lines required. + //codewords -> Output patterns with the respective codewords. + //totalNoBits -> Total no. of bits required to create the circuit + // r -> additional variables/bits required to decode r MSB bits of the circuit. + + const auto n = tt.nInputs(); + const auto m = tt.nOutputs(); + + const auto [codewords, k1] = encodeHuffman(tt); + + const auto totalNoBits = std::max(n, m + k1); + const auto r = totalNoBits - tt.nOutputs(); + + augmentWithConstants(tt, totalNoBits); const auto ttDD = buildDD(tt, dd); EXPECT_TRUE(ttDD.p != nullptr); - DDSynthesizer synthesizer(tt.nInputs()); - const auto& qc = synthesizer.synthesize(ttDD, dd); + DDSynthesizer synthesizer(totalNoBits); + + // codewords, r, m required for decoding purposes. + const auto& qc = synthesizer.synthesize(ttDD, codewords, r, m, dd); + + //Expected Truth table + for (const auto& [input, output]: ttOri) { + auto inCube(input); + for (auto i = 0U; i < (totalNoBits - input.size()); i++) { + inCube.insertZero(); + } + TruthTable::Cube outCube(output); + outCube.resize(totalNoBits); + ttExpected.try_emplace(inCube, outCube); + } buildTruthTable(qc, ttqc); - EXPECT_TRUE(TruthTable::equal(tt, ttqc)); + EXPECT_TRUE(TruthTable::equal(ttExpected, ttqc)); + std::cout << totalNoBits << "\n"; std::cout << synthesizer.numGate() << "\n"; std::cout << synthesizer.getExecutionTime() << "\n"; } diff --git a/test/unittests/test_huffman.cpp b/test/unittests/test_huffman.cpp index 1259eb93..e653681e 100644 --- a/test/unittests/test_huffman.cpp +++ b/test/unittests/test_huffman.cpp @@ -121,14 +121,14 @@ TEST_F(TestHuff, HUFF2) { EXPECT_EQ(tt.nInputs(), 2U); - augmentWithConstants(tt); + augmentWithConstants(tt, 4U); - EXPECT_EQ(tt.nInputs(), 3U); + EXPECT_EQ(tt.nInputs(), 4U); - const std::vector augInput{0b000U, 0b001U, 0b010U, 0b011U}; + const std::vector augInput{0b0000U, 0b0001U, 0b0010U, 0b0011U}; for (const auto& in2: augInput) { - auto search4 = tt.find(in2, 3U); + auto search4 = tt.find(in2, 4U); EXPECT_TRUE(search4 != tt.end()); } From ec69274a23c13e3d9cba0030d209de075311d12c Mon Sep 17 00:00:00 2001 From: SmaranTum Date: Mon, 5 Dec 2022 16:35:19 +0100 Subject: [PATCH 2/6] Decoder functionality included. Accordingly the signatures of certain functions are changed. --- .../simulation/circuit_to_truthtable.hpp | 2 +- include/algorithms/synthesis/encoding.hpp | 4 +++- include/core/truthTable/truth_table.hpp | 5 +++-- .../simulation/circuit_to_truthtable.cpp | 6 +++--- src/algorithms/synthesis/encoding.cpp | 19 +++++++++++++------ 5 files changed, 23 insertions(+), 13 deletions(-) diff --git a/include/algorithms/simulation/circuit_to_truthtable.hpp b/include/algorithms/simulation/circuit_to_truthtable.hpp index 0579ebd5..edb4613a 100644 --- a/include/algorithms/simulation/circuit_to_truthtable.hpp +++ b/include/algorithms/simulation/circuit_to_truthtable.hpp @@ -5,6 +5,6 @@ namespace syrec { - auto buildTruthTable(const qc::QuantumComputation& qc, TruthTable& tt) -> void; + auto buildTruthTable(const qc::QuantumComputation* qc, TruthTable& tt) -> void; } // namespace syrec diff --git a/include/algorithms/synthesis/encoding.hpp b/include/algorithms/synthesis/encoding.hpp index d46a50cf..ecdbed5a 100644 --- a/include/algorithms/synthesis/encoding.hpp +++ b/include/algorithms/synthesis/encoding.hpp @@ -38,7 +38,9 @@ namespace syrec { auto extend(TruthTable& tt) -> void; - auto encodeHuffman(TruthTable& tt) -> std::tuple; + auto completeTruthTable(TruthTable& tt, std::size_t const& totalNoBits) -> void; + + auto encodeHuffman(TruthTable& tt) -> std::pair; auto augmentWithConstants(TruthTable& tt, std::size_t const& nBits) -> void; diff --git a/include/core/truthTable/truth_table.hpp b/include/core/truthTable/truth_table.hpp index 4c120f15..bbd3b18c 100644 --- a/include/core/truthTable/truth_table.hpp +++ b/include/core/truthTable/truth_table.hpp @@ -239,8 +239,9 @@ namespace syrec { CubeMap cubeMap{}; public: - TruthTable() = default; - TruthTable(TruthTable& tt) = default; + TruthTable() = default; + TruthTable(TruthTable& tt) = default; + TruthTable(TruthTable const& tt) = default; auto operator==(const TruthTable& tt) const -> bool { return (cubeMap == tt.cubeMap); diff --git a/src/algorithms/simulation/circuit_to_truthtable.cpp b/src/algorithms/simulation/circuit_to_truthtable.cpp index 4665a2a3..576912aa 100644 --- a/src/algorithms/simulation/circuit_to_truthtable.cpp +++ b/src/algorithms/simulation/circuit_to_truthtable.cpp @@ -4,8 +4,8 @@ namespace syrec { - auto buildTruthTable(const qc::QuantumComputation& qc, TruthTable& tt) -> void { - const auto nBits = qc.getNqubits(); + auto buildTruthTable(const qc::QuantumComputation* qc, TruthTable& tt) -> void { + const auto nBits = qc->getNqubits(); assert(nBits < 65U); auto dd = std::make_unique>(nBits); @@ -18,7 +18,7 @@ namespace syrec { 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 out = dd::simulate(qc, inEdge, dd, 1); const auto outString = out.begin()->first; tt.try_emplace(inCube, TruthTable::Cube::fromString(outString)); diff --git a/src/algorithms/synthesis/encoding.cpp b/src/algorithms/synthesis/encoding.cpp index 0463233b..539f79bf 100644 --- a/src/algorithms/synthesis/encoding.cpp +++ b/src/algorithms/synthesis/encoding.cpp @@ -40,7 +40,15 @@ namespace syrec { } } - auto encodeHuffman(TruthTable& tt) -> std::tuple { + auto completeTruthTable(TruthTable& ttExpected, std::size_t const& totalNoBits) -> void { + extend(ttExpected); + for (auto& [input, output]: ttExpected) { + output.resize(totalNoBits); + } + augmentWithConstants(ttExpected, totalNoBits); + } + + auto encodeHuffman(TruthTable& tt) -> std::pair { std::map outputFreq; for (const auto& [input, output]: tt) { outputFreq[output]++; @@ -48,7 +56,7 @@ namespace syrec { // if the truth table function is already reversible, no encoding is necessary if (outputFreq.size() == tt.size()) { - return std::make_tuple(TruthTable::CubeMap{}, 0U); + return {TruthTable::CubeMap{}, 0U}; } // create a priority queue for building the Huffman tree @@ -126,19 +134,18 @@ namespace syrec { output = encoding[output]; } - return std::make_tuple(encoding, additionalLines); + return {encoding, additionalLines}; } auto augmentWithConstants(TruthTable& tt, std::size_t const& nBits) -> void { - //add necessary constant inputs to the outputs based on the total number of bits (nBits) const auto ancillaBits = nBits - tt.nOutputs(); + for (auto& [input, output]: tt) { + // add necessary constant inputs to the outputs based on the total number of bits (nBits). for (auto i = 0U; i < ancillaBits; i++) { output.insertZero(); } - } - for (auto const& [input, output]: tt) { const auto inputSize = input.size(); const auto outputSize = output.size(); if (inputSize >= outputSize) { From 770179a4397dab1ea2fdc7e508c74da40018954c Mon Sep 17 00:00:00 2001 From: SmaranTum Date: Mon, 5 Dec 2022 16:55:50 +0100 Subject: [PATCH 3/6] Changes based on review comments. Included general purpose truth table synthesizer. Refactored tests. --- include/algorithms/synthesis/dd_synthesis.hpp | 37 ++++-- src/algorithms/synthesis/dd_synthesis.cpp | 113 +++++++++++------- test/unittests/test_dd_synthesis.cpp | 10 +- test/unittests/test_dd_synthesis_dc.cpp | 58 ++------- 4 files changed, 114 insertions(+), 104 deletions(-) diff --git a/include/algorithms/synthesis/dd_synthesis.hpp b/include/algorithms/synthesis/dd_synthesis.hpp index eff5b852..0694ecd6 100644 --- a/include/algorithms/synthesis/dd_synthesis.hpp +++ b/include/algorithms/synthesis/dd_synthesis.hpp @@ -2,6 +2,7 @@ #include "QuantumComputation.hpp" #include "algorithms/optimization/esop_minimization.hpp" +#include "algorithms/synthesis/encoding.hpp" #include "core/truthTable/truth_table.hpp" #include @@ -14,10 +15,15 @@ namespace syrec { public: DDSynthesizer() = default; - explicit DDSynthesizer(const std::size_t nqubits): - qc(nqubits) {} + explicit DDSynthesizer(TruthTable const& tt): + m(tt.nOutputs()), totalNoBits(tt.nOutputs()) {} - auto synthesize(dd::mEdge src, TruthTable::CubeMap const& codeword, std::size_t const& r, std::size_t const& m, std::unique_ptr>& dd) -> qc::QuantumComputation&; + auto synthesize(TruthTable const& tt) -> std::shared_ptr; + auto synthesize(dd::mEdge src, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void; + + [[nodiscard]] auto getNbits() const -> std::size_t { + return totalNoBits; + } [[nodiscard]] auto numGate() const -> std::size_t { return numGates; @@ -28,9 +34,15 @@ namespace syrec { } private: - double runtime = 0.; - std::size_t numGates = 0U; - qc::QuantumComputation qc; + double runtime = 0.; + std::size_t numGates = 0U; + + // m -> No. of primary outputs. + // totalNoBits -> Total no. of bits required to create the circuit + + std::size_t m = 0U; + std::size_t totalNoBits = 0U; + bool garbageFlag = false; 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; @@ -42,23 +54,22 @@ namespace syrec { static auto completeUniCubes(TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set& uniqueCubeVec) -> void; - auto applyOperation(dd::QubitCount const& totalBits, dd::Qubit const& targetBit, dd::mEdge& to, dd::Controls const& ctrl, std::unique_ptr>& dd) -> void; + auto applyOperation(dd::QubitCount const& totalBits, dd::Qubit const& targetBit, dd::mEdge& to, dd::Controls const& ctrl, std::unique_ptr>& dd, const std::shared_ptr& qc) -> 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; 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, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, std::unique_ptr>& dd) -> dd::mEdge; + auto swapPaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge; - auto shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, bool& changePaths, std::unique_ptr>& dd) -> dd::mEdge; + auto shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, bool& changePaths, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge; static auto terminate(dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec) -> bool; - auto unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& dd) -> dd::mEdge; - auto shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd) -> dd::mEdge; + auto unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge; + auto shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge; - auto decoder(TruthTable::CubeMap const& codeword, std::size_t const& r, std::size_t const& m, std::unique_ptr>& dd) -> void; - auto synthesizeDD(dd::mEdge src, std::unique_ptr>& dd, std::size_t const& m, bool flag) -> void; + auto decoder(TruthTable::CubeMap const& codewords, std::size_t const& r, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void; }; } // namespace syrec diff --git a/src/algorithms/synthesis/dd_synthesis.cpp b/src/algorithms/synthesis/dd_synthesis.cpp index f1719f35..5665452e 100644 --- a/src/algorithms/synthesis/dd_synthesis.cpp +++ b/src/algorithms/synthesis/dd_synthesis.cpp @@ -1,5 +1,7 @@ #include "algorithms/synthesis/dd_synthesis.hpp" +#include "algorithms/synthesis/encoding.hpp" + using namespace dd::literals; namespace syrec { @@ -215,7 +217,7 @@ namespace syrec { } // 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) -> void { + auto DDSynthesizer::applyOperation(dd::QubitCount const& totalBits, dd::Qubit const& targetBit, dd::mEdge& to, dd::Controls const& ctrl, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void { // create operation and corresponding decision diagram auto op = std::make_unique(totalBits, ctrl, targetBit, qc::X); const auto opDD = dd::getDD(op.get(), dd); @@ -226,14 +228,14 @@ namespace syrec { to = tmp; dd->garbageCollect(); - qc.emplace_back(op); + qc->emplace_back(op); ++numGates; } // This algorithm swaps the paths present in the p' edge to the n edge and vice versa. // If n' and p paths exists, we move on to P2 algorithm // 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::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, std::unique_ptr>& dd) -> dd::mEdge { + auto DDSynthesizer::swapPaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge { if (p2SigVec.size() > p1SigVec.size() || (p2SigVec.empty() && p1SigVec.empty())) { if (p2SigVec.empty()) { if (p3SigVec.empty() && p4SigVec.empty() && ((!current.p->e[0].isZeroTerminal() && current.p->e[1].isZeroTerminal()) || (!current.p->e[3].isZeroTerminal() && current.p->e[2].isZeroTerminal()))) { @@ -256,7 +258,7 @@ namespace syrec { for (auto const& rootVec: rootSolution) { dd::Controls ctrlFinal; controlRoot(current, ctrlFinal, rootVec); - applyOperation(nQubits, current.p->v, src, ctrlFinal, dd); + applyOperation(nQubits, current.p->v, src, ctrlFinal, dd, qc); } } return src; @@ -265,7 +267,7 @@ namespace syrec { // This algorithm moves the unique paths present in the p' edge to the n edge. // If there are no unique paths in p' edge, the unique paths present in the n' edge are moved to the p edge if required. // 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::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, bool& changePaths, std::unique_ptr>& dd) -> dd::mEdge { + auto DDSynthesizer::shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, bool& changePaths, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge { if (p2SigVec.empty()) { if (p3SigVec.empty() || (p1SigVec == p3SigVec && p2SigVec == p4SigVec)) { return src; @@ -307,7 +309,7 @@ namespace syrec { for (auto const& rootVec: rootSolution) { dd::Controls ctrlFinal = ctrlNonRoot; controlRoot(current, ctrlFinal, rootVec); - applyOperation(nQubits, current.p->v, src, ctrlFinal, dd); + applyOperation(nQubits, current.p->v, src, ctrlFinal, dd, qc); } } return src; @@ -325,7 +327,7 @@ namespace syrec { // This algorithm modifies the non-unique paths present in the p' or n (based on changePaths) 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::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& dd) -> dd::mEdge { + auto DDSynthesizer::unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge { TruthTable::Cube repeatedCube; for (auto const& p2Obj: p2SigVec) { if (const auto it = std::find(p1SigVec.begin(), p1SigVec.end(), p2Obj); it != p1SigVec.end()) { @@ -374,7 +376,7 @@ namespace syrec { for (std::size_t i = 0; i < targetSize; ++i) { if (targetVec[i].has_value() && *(targetVec[i])) { - applyOperation(nQubits, static_cast(static_cast(current.p->v) - (i + 1U)), src, ctrlFinal, dd); + applyOperation(nQubits, static_cast(static_cast(current.p->v) - (i + 1U)), src, ctrlFinal, dd, qc); } } } @@ -383,7 +385,7 @@ namespace syrec { // This algorithm ensures that the `current` node has the identity structure. // Refer to algorithm P of http://www.informatik.uni-bremen.de/agra/doc/konf/12aspdac_qmdd_synth_rev.pdf) - auto DDSynthesizer::shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd) -> dd::mEdge { + auto DDSynthesizer::shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge { if (dd::mNode::isTerminal(current.p)) { return src; } @@ -403,13 +405,13 @@ namespace syrec { auto changePaths = false; // P1 algorithm. - if (const auto srcSwapped = swapPaths(src, current, p1SigVec, p2SigVec, p3SigVec, p4SigVec, dd); srcSwapped != src) { + if (const auto srcSwapped = swapPaths(src, current, p1SigVec, p2SigVec, p3SigVec, p4SigVec, dd, qc); srcSwapped != src) { return srcSwapped; } // P2 algorithm. // If there are no unique paths in p' edge, the unique paths present in the n' edge are moved to the p edge if required. changePaths flag is set accordingly. - if (const auto srcUnique = shiftUniquePaths(src, current, p1SigVec, p2SigVec, p3SigVec, p4SigVec, changePaths, dd); srcUnique != src) { + if (const auto srcUnique = shiftUniquePaths(src, current, p1SigVec, p2SigVec, p3SigVec, p4SigVec, changePaths, dd, qc); srcUnique != src) { return srcUnique; } @@ -421,20 +423,18 @@ namespace syrec { // P4 algorithm. // if changePaths flag is set, p and n' edges are considered instead of n and p' edges. if (changePaths) { - return unifyPath(src, current, p4SigVec, p3SigVec, changePaths, dd); + return unifyPath(src, current, p4SigVec, p3SigVec, changePaths, dd, qc); } - return unifyPath(src, current, p1SigVec, p2SigVec, changePaths, dd); + return unifyPath(src, current, p1SigVec, p2SigVec, changePaths, dd, qc); } // Refer to the decoder algorithm of https://www.cda.cit.tum.de/files/eda/2018_aspdac_coding_techniques_in_synthesis.pdf. - auto DDSynthesizer::decoder(TruthTable::CubeMap const& codeword, std::size_t const& r, std::size_t const& m, std::unique_ptr>& dd) -> void { - const auto codeLength = codeword.begin()->second.size(); - const auto totalBits = qc.getNqubits(); - // if r = 0, skip to decoder part 2. - - //Decoder part 1. - if (r > 0U) { - for (const auto& [pattern, code]: codeword) { + auto DDSynthesizer::decoder(TruthTable::CubeMap const& codewords, std::size_t const& r, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void { + const auto codeLength = codewords.begin()->second.size(); + + // decode the r most significant bits of the original output pattern. + if (r != 0U) { + for (const auto& [pattern, code]: codewords) { TruthTable::Cube targetCube(pattern.begin(), pattern.begin() + static_cast(r)); dd::Controls ctrl; @@ -449,15 +449,15 @@ namespace syrec { for (std::size_t i = 0U; i < targetSize; ++i) { if (targetCube[i].has_value() && *(targetCube[i])) { - auto op = std::make_unique(totalBits, ctrl, static_cast((static_cast(totalBits) - 1U) - i), qc::X); - qc.emplace_back(op); + const auto targetBit = static_cast((totalNoBits - 1U) - i); + qc->x(targetBit, ctrl); ++numGates; } } } } - //Decoder part 2. + // decode the remaining (m − r) primary outputs. const auto correctionBits = m - r; if (correctionBits == 0U) { @@ -466,9 +466,10 @@ namespace syrec { TruthTable ttCorrection{}; - for (const auto& [pattern, code]: codeword) { + for (const auto& [pattern, code]: codewords) { TruthTable::Cube outCube(pattern); - outCube.resize(totalBits); + outCube.resize(totalNoBits); + TruthTable::Cube inCube(pattern.begin(), pattern.begin() + static_cast(r)); for (auto i = 0U; i < codeLength; i++) { inCube.emplace_back(code[i]); @@ -486,19 +487,20 @@ namespace syrec { } const auto ttCorrectionDD = buildDD(newTT, dd); - synthesizeDD(ttCorrectionDD, dd, m, true); + garbageFlag = true; + synthesize(ttCorrectionDD, dd, qc); } // This function returns the operations required to synthesize the DD. // flag -> If true, the synthesis is stopped after the nodeThreshold is reached. // m -> No. of primary outputs. - auto DDSynthesizer::synthesizeDD(dd::mEdge src, std::unique_ptr>& dd, std::size_t const& m, bool flag) -> void { + auto DDSynthesizer::synthesize(dd::mEdge src, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void { if (src.p == nullptr || src.p->isIdentity() || dcNodeCondition(src)) { return; } - // The Node after which the synthesis can be terminated without affecting the functionality. - const auto nodeThreshold = static_cast(qc.getNqubits()) - static_cast(m); + // the threshold after which the outputs are considered to be garbage. + const auto garbageThreshold = static_cast(totalNoBits) - static_cast(m); // This following ensures that the `src` node resembles an identity structure. // Refer to algorithm Q of http://www.informatik.uni-bremen.de/agra/doc/konf/12aspdac_qmdd_synth_rev.pdf. @@ -515,12 +517,14 @@ namespace syrec { // set of nodes that have already been processed. std::unordered_set visited{}; + const auto start = std::chrono::steady_clock::now(); + // while there are nodes left to process. while (!queue.empty()) { const auto current = queue.front(); - //The synthesis is stopped after the nodeThreshold is reached (considered only while synthesizing the decoder) - if (current.p->v == nodeThreshold - 1 && flag) { + // if the garbageFlag is true, the synthesis is terminated once the garbage threshold is reached. + if (garbageFlag && current.p->v == garbageThreshold - 1) { break; } @@ -537,7 +541,7 @@ namespace syrec { dd->incRef(src); // perform the shifting paths algorithm. - const auto srcShifted = shiftingPaths(src, current, dd); + const auto srcShifted = shiftingPaths(src, current, dd, qc); const auto pathsShifted = (srcShifted != src); // decrement reference count of `src` node again and trigger garbage collection. @@ -566,25 +570,48 @@ namespace syrec { } } } + + runtime = static_cast((std::chrono::steady_clock::now() - start).count()); } - auto DDSynthesizer::synthesize(dd::mEdge src, TruthTable::CubeMap const& codeword, std::size_t const& r, std::size_t const& m, std::unique_ptr>& dd) -> qc::QuantumComputation& { - qc.clear(); - runtime = 0.; - numGates = 0U; + auto DDSynthesizer::synthesize(TruthTable const& tt) -> std::shared_ptr { + runtime = 0.; + numGates = 0U; + garbageFlag = false; + + // no. of primary inputs. + const auto n = tt.nInputs(); + TruthTable ttCpy(tt); + + extend(ttCpy); + + // codewords -> Output patterns with the respective codewords. + // k1 -> Minimum no. of additional lines required. + const auto [codewords, k1] = encodeHuffman(ttCpy); + + totalNoBits = std::max(n, m + k1); + const auto r = totalNoBits - ttCpy.nOutputs(); + + augmentWithConstants(ttCpy, totalNoBits); + + auto dd = std::make_unique>(totalNoBits); + const auto src = buildDD(ttCpy, dd); + + // clear ttCpy as early as possible. + ttCpy.clear(); const auto start = std::chrono::steady_clock::now(); - synthesizeDD(src, dd, m, false); + auto qc = std::make_shared(totalNoBits); + synthesize(src, dd, qc); - // if codeword is empty, then function is src edge realizes a reversible function by default. - if (!codeword.empty()) { - // synthesizing decoder circuit. - decoder(codeword, r, m, dd); + // if codeword is not empty, the above synthesized encoded function should be decoded. + if (!codewords.empty()) { + // synthesizing the corresponding decoder circuit. + decoder(codewords, r, dd, qc); } runtime = static_cast((std::chrono::steady_clock::now() - start).count()); - return qc; } diff --git a/test/unittests/test_dd_synthesis.cpp b/test/unittests/test_dd_synthesis.cpp index 88193684..3bc5ba95 100644 --- a/test/unittests/test_dd_synthesis.cpp +++ b/test/unittests/test_dd_synthesis.cpp @@ -60,10 +60,14 @@ TEST_P(TestDDSynth, GenericDDSynthesisTest) { const auto ttDD = buildDD(tt, dd); EXPECT_TRUE(ttDD.p != nullptr); + DDSynthesizer synthesizer(tt); + const auto totalNoBits = synthesizer.getNbits(); - DDSynthesizer synthesizer(tt.nInputs()); - const auto& qc = synthesizer.synthesize(ttDD, {}, 0U, tt.nOutputs(), dd); - const auto& qcDD = dd::buildFunctionality(&qc, dd); + auto qc = std::make_shared(totalNoBits); + + synthesizer.synthesize(ttDD, dd, qc); + auto const* qcPtr = qc.get(); + const auto& qcDD = dd::buildFunctionality(qcPtr, dd); EXPECT_EQ(ttDD, qcDD); std::cout << synthesizer.numGate() << "\n"; diff --git a/test/unittests/test_dd_synthesis_dc.cpp b/test/unittests/test_dd_synthesis_dc.cpp index c4ece286..cbe19894 100644 --- a/test/unittests/test_dd_synthesis_dc.cpp +++ b/test/unittests/test_dd_synthesis_dc.cpp @@ -10,12 +10,11 @@ using namespace syrec; class TestDDSynthDc: public testing::TestWithParam { protected: - TruthTable tt{}; - TruthTable ttExpected{}; - TruthTable ttqc{}; - std::string testCircuitsDir = "./circuits/"; - std::unique_ptr> dd = std::make_unique>(15U); - std::string fileName; + TruthTable tt{}; + TruthTable ttExpected{}; + TruthTable ttqc{}; + std::string testCircuitsDir = "./circuits/"; + std::string fileName; void SetUp() override { fileName = testCircuitsDir + GetParam() + ".pla"; @@ -60,51 +59,20 @@ INSTANTIATE_TEST_SUITE_P(TestDDSynth, TestDDSynthDc, TEST_P(TestDDSynthDc, GenericDDSynthesisDcTest) { EXPECT_TRUE(readPla(tt, fileName)); - extend(tt); - TruthTable const ttOri(tt); //unchanged Truth Table. + DDSynthesizer synthesizer(tt); + const auto& qc = synthesizer.synthesize(tt); + const auto totalNoBits = synthesizer.getNbits(); + auto const* qcPtr = qc.get(); - //n -> No. of primary inputs. - //m -> No. of primary outputs. - //k1 -> Minimum no. of additional lines required. - //codewords -> Output patterns with the respective codewords. - //totalNoBits -> Total no. of bits required to create the circuit - // r -> additional variables/bits required to decode r MSB bits of the circuit. + // generate the complete truth table. + TruthTable ttExpected{tt}; + completeTruthTable(ttExpected, totalNoBits); - const auto n = tt.nInputs(); - const auto m = tt.nOutputs(); - - const auto [codewords, k1] = encodeHuffman(tt); - - const auto totalNoBits = std::max(n, m + k1); - const auto r = totalNoBits - tt.nOutputs(); - - augmentWithConstants(tt, totalNoBits); - - const auto ttDD = buildDD(tt, dd); - EXPECT_TRUE(ttDD.p != nullptr); - - DDSynthesizer synthesizer(totalNoBits); - - // codewords, r, m required for decoding purposes. - const auto& qc = synthesizer.synthesize(ttDD, codewords, r, m, dd); - - //Expected Truth table - for (const auto& [input, output]: ttOri) { - auto inCube(input); - for (auto i = 0U; i < (totalNoBits - input.size()); i++) { - inCube.insertZero(); - } - TruthTable::Cube outCube(output); - outCube.resize(totalNoBits); - ttExpected.try_emplace(inCube, outCube); - } - - buildTruthTable(qc, ttqc); + buildTruthTable(qcPtr, ttqc); EXPECT_TRUE(TruthTable::equal(ttExpected, ttqc)); - std::cout << totalNoBits << "\n"; std::cout << synthesizer.numGate() << "\n"; std::cout << synthesizer.getExecutionTime() << "\n"; } From c57bd8e542e362770f38bf55f671bf80a75c26c3 Mon Sep 17 00:00:00 2001 From: SmaranTum Date: Tue, 6 Dec 2022 00:24:11 +0100 Subject: [PATCH 4/6] Changes based on review comments. --- .../simulation/circuit_to_truthtable.hpp | 2 +- include/algorithms/synthesis/dd_synthesis.hpp | 39 +++++---- include/algorithms/synthesis/encoding.hpp | 4 +- include/core/truthTable/truth_table.hpp | 4 - .../simulation/circuit_to_truthtable.cpp | 6 +- src/algorithms/synthesis/dd_synthesis.cpp | 82 +++++++++---------- src/algorithms/synthesis/encoding.cpp | 21 ++--- test/unittests/test_dd_synthesis.cpp | 10 +-- test/unittests/test_dd_synthesis_dc.cpp | 18 ++-- 9 files changed, 84 insertions(+), 102 deletions(-) diff --git a/include/algorithms/simulation/circuit_to_truthtable.hpp b/include/algorithms/simulation/circuit_to_truthtable.hpp index edb4613a..0579ebd5 100644 --- a/include/algorithms/simulation/circuit_to_truthtable.hpp +++ b/include/algorithms/simulation/circuit_to_truthtable.hpp @@ -5,6 +5,6 @@ namespace syrec { - auto buildTruthTable(const qc::QuantumComputation* qc, TruthTable& tt) -> void; + auto buildTruthTable(const qc::QuantumComputation& qc, TruthTable& tt) -> void; } // namespace syrec diff --git a/include/algorithms/synthesis/dd_synthesis.hpp b/include/algorithms/synthesis/dd_synthesis.hpp index 0694ecd6..3cbf0ddc 100644 --- a/include/algorithms/synthesis/dd_synthesis.hpp +++ b/include/algorithms/synthesis/dd_synthesis.hpp @@ -13,18 +13,13 @@ namespace syrec { class DDSynthesizer { public: - DDSynthesizer() = default; - - explicit DDSynthesizer(TruthTable const& tt): - m(tt.nOutputs()), totalNoBits(tt.nOutputs()) {} - - auto synthesize(TruthTable const& tt) -> std::shared_ptr; - auto synthesize(dd::mEdge src, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void; - - [[nodiscard]] auto getNbits() const -> std::size_t { - return totalNoBits; + static auto synthesize(const TruthTable& tt) -> std::shared_ptr { + DDSynthesizer synthesizer{}; + return synthesizer.synthesizeTT(tt); } + auto synthesize(dd::mEdge src, std::unique_ptr>& dd) -> std::shared_ptr; + [[nodiscard]] auto numGate() const -> std::size_t { return numGates; } @@ -34,14 +29,20 @@ namespace syrec { } private: - double runtime = 0.; - std::size_t numGates = 0U; + double runtime = 0.; + std::size_t numGates = 0U; + std::unique_ptr> ddSynth; + std::shared_ptr qc; + // n -> No. of primary inputs. // m -> No. of primary outputs. // totalNoBits -> Total no. of bits required to create the circuit + // r -> Additional variables/bits required to decode the output patterns. + std::size_t n = 0U; std::size_t m = 0U; std::size_t totalNoBits = 0U; + std::size_t r = 0U; bool garbageFlag = false; auto pathFromSrcDst(dd::mEdge const& src, dd::mNode* const& dst, TruthTable::Cube::Set& sigVec) const -> void; @@ -54,22 +55,24 @@ namespace syrec { static auto completeUniCubes(TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set& uniqueCubeVec) -> void; - auto applyOperation(dd::QubitCount const& totalBits, dd::Qubit const& targetBit, dd::mEdge& to, dd::Controls const& ctrl, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void; + auto applyOperation(dd::QubitCount const& totalBits, dd::Qubit const& targetBit, dd::mEdge& to, dd::Controls const& ctrl, std::unique_ptr>& 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; 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, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge; + auto swapPaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, std::unique_ptr>& dd) -> dd::mEdge; - auto shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, bool& changePaths, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge; + auto shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, bool& changePaths, std::unique_ptr>& dd) -> dd::mEdge; static auto terminate(dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec) -> bool; - auto unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge; - auto shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge; + auto unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& dd) -> dd::mEdge; + auto shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd) -> dd::mEdge; + + auto decoder(TruthTable::CubeMap const& codewords, std::unique_ptr>& dd) -> void; - auto decoder(TruthTable::CubeMap const& codewords, std::size_t const& r, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void; + auto synthesizeTT(TruthTable tt) -> std::shared_ptr; }; } // namespace syrec diff --git a/include/algorithms/synthesis/encoding.hpp b/include/algorithms/synthesis/encoding.hpp index ecdbed5a..47945b2d 100644 --- a/include/algorithms/synthesis/encoding.hpp +++ b/include/algorithms/synthesis/encoding.hpp @@ -38,10 +38,8 @@ namespace syrec { auto extend(TruthTable& tt) -> void; - auto completeTruthTable(TruthTable& tt, std::size_t const& totalNoBits) -> void; - auto encodeHuffman(TruthTable& tt) -> std::pair; - auto augmentWithConstants(TruthTable& tt, std::size_t const& nBits) -> void; + auto augmentWithConstants(TruthTable& tt, std::size_t const& nBits, bool dc = false) -> void; } //namespace syrec diff --git a/include/core/truthTable/truth_table.hpp b/include/core/truthTable/truth_table.hpp index bbd3b18c..a5aa0ff2 100644 --- a/include/core/truthTable/truth_table.hpp +++ b/include/core/truthTable/truth_table.hpp @@ -239,10 +239,6 @@ namespace syrec { CubeMap cubeMap{}; public: - TruthTable() = default; - TruthTable(TruthTable& tt) = default; - TruthTable(TruthTable const& tt) = default; - auto operator==(const TruthTable& tt) const -> bool { return (cubeMap == tt.cubeMap); } diff --git a/src/algorithms/simulation/circuit_to_truthtable.cpp b/src/algorithms/simulation/circuit_to_truthtable.cpp index 576912aa..4665a2a3 100644 --- a/src/algorithms/simulation/circuit_to_truthtable.cpp +++ b/src/algorithms/simulation/circuit_to_truthtable.cpp @@ -4,8 +4,8 @@ namespace syrec { - auto buildTruthTable(const qc::QuantumComputation* qc, TruthTable& tt) -> void { - const auto nBits = qc->getNqubits(); + auto buildTruthTable(const qc::QuantumComputation& qc, TruthTable& tt) -> void { + const auto nBits = qc.getNqubits(); assert(nBits < 65U); auto dd = std::make_unique>(nBits); @@ -18,7 +18,7 @@ namespace syrec { 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 out = dd::simulate(&qc, inEdge, dd, 1); const auto outString = out.begin()->first; tt.try_emplace(inCube, TruthTable::Cube::fromString(outString)); diff --git a/src/algorithms/synthesis/dd_synthesis.cpp b/src/algorithms/synthesis/dd_synthesis.cpp index 5665452e..b8a95182 100644 --- a/src/algorithms/synthesis/dd_synthesis.cpp +++ b/src/algorithms/synthesis/dd_synthesis.cpp @@ -217,7 +217,7 @@ namespace syrec { } // 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, const std::shared_ptr& qc) -> void { + auto DDSynthesizer::applyOperation(dd::QubitCount const& totalBits, dd::Qubit const& targetBit, dd::mEdge& to, dd::Controls const& ctrl, std::unique_ptr>& dd) -> void { // create operation and corresponding decision diagram auto op = std::make_unique(totalBits, ctrl, targetBit, qc::X); const auto opDD = dd::getDD(op.get(), dd); @@ -235,7 +235,7 @@ namespace syrec { // This algorithm swaps the paths present in the p' edge to the n edge and vice versa. // If n' and p paths exists, we move on to P2 algorithm // 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::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge { + auto DDSynthesizer::swapPaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, std::unique_ptr>& dd) -> dd::mEdge { if (p2SigVec.size() > p1SigVec.size() || (p2SigVec.empty() && p1SigVec.empty())) { if (p2SigVec.empty()) { if (p3SigVec.empty() && p4SigVec.empty() && ((!current.p->e[0].isZeroTerminal() && current.p->e[1].isZeroTerminal()) || (!current.p->e[3].isZeroTerminal() && current.p->e[2].isZeroTerminal()))) { @@ -258,7 +258,7 @@ namespace syrec { for (auto const& rootVec: rootSolution) { dd::Controls ctrlFinal; controlRoot(current, ctrlFinal, rootVec); - applyOperation(nQubits, current.p->v, src, ctrlFinal, dd, qc); + applyOperation(nQubits, current.p->v, src, ctrlFinal, dd); } } return src; @@ -267,7 +267,7 @@ namespace syrec { // This algorithm moves the unique paths present in the p' edge to the n edge. // If there are no unique paths in p' edge, the unique paths present in the n' edge are moved to the p edge if required. // 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::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, bool& changePaths, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge { + auto DDSynthesizer::shiftUniquePaths(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, TruthTable::Cube::Set const& p3SigVec, TruthTable::Cube::Set const& p4SigVec, bool& changePaths, std::unique_ptr>& dd) -> dd::mEdge { if (p2SigVec.empty()) { if (p3SigVec.empty() || (p1SigVec == p3SigVec && p2SigVec == p4SigVec)) { return src; @@ -309,7 +309,7 @@ namespace syrec { for (auto const& rootVec: rootSolution) { dd::Controls ctrlFinal = ctrlNonRoot; controlRoot(current, ctrlFinal, rootVec); - applyOperation(nQubits, current.p->v, src, ctrlFinal, dd, qc); + applyOperation(nQubits, current.p->v, src, ctrlFinal, dd); } } return src; @@ -327,7 +327,7 @@ namespace syrec { // This algorithm modifies the non-unique paths present in the p' or n (based on changePaths) 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::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge { + auto DDSynthesizer::unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& 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()) { @@ -376,7 +376,7 @@ namespace syrec { for (std::size_t i = 0; i < targetSize; ++i) { if (targetVec[i].has_value() && *(targetVec[i])) { - applyOperation(nQubits, static_cast(static_cast(current.p->v) - (i + 1U)), src, ctrlFinal, dd, qc); + applyOperation(nQubits, static_cast(static_cast(current.p->v) - (i + 1U)), src, ctrlFinal, dd); } } } @@ -385,7 +385,7 @@ namespace syrec { // This algorithm ensures that the `current` node has the identity structure. // Refer to algorithm P of http://www.informatik.uni-bremen.de/agra/doc/konf/12aspdac_qmdd_synth_rev.pdf) - auto DDSynthesizer::shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd, const std::shared_ptr& qc) -> dd::mEdge { + auto DDSynthesizer::shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd) -> dd::mEdge { if (dd::mNode::isTerminal(current.p)) { return src; } @@ -405,13 +405,13 @@ namespace syrec { auto changePaths = false; // P1 algorithm. - if (const auto srcSwapped = swapPaths(src, current, p1SigVec, p2SigVec, p3SigVec, p4SigVec, dd, qc); srcSwapped != src) { + if (const auto srcSwapped = swapPaths(src, current, p1SigVec, p2SigVec, p3SigVec, p4SigVec, dd); srcSwapped != src) { return srcSwapped; } // P2 algorithm. // If there are no unique paths in p' edge, the unique paths present in the n' edge are moved to the p edge if required. changePaths flag is set accordingly. - if (const auto srcUnique = shiftUniquePaths(src, current, p1SigVec, p2SigVec, p3SigVec, p4SigVec, changePaths, dd, qc); srcUnique != src) { + if (const auto srcUnique = shiftUniquePaths(src, current, p1SigVec, p2SigVec, p3SigVec, p4SigVec, changePaths, dd); srcUnique != src) { return srcUnique; } @@ -423,13 +423,13 @@ namespace syrec { // P4 algorithm. // if changePaths flag is set, p and n' edges are considered instead of n and p' edges. if (changePaths) { - return unifyPath(src, current, p4SigVec, p3SigVec, changePaths, dd, qc); + return unifyPath(src, current, p4SigVec, p3SigVec, changePaths, dd); } - return unifyPath(src, current, p1SigVec, p2SigVec, changePaths, dd, qc); + return unifyPath(src, current, p1SigVec, p2SigVec, changePaths, dd); } // Refer to the decoder algorithm of https://www.cda.cit.tum.de/files/eda/2018_aspdac_coding_techniques_in_synthesis.pdf. - auto DDSynthesizer::decoder(TruthTable::CubeMap const& codewords, std::size_t const& r, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void { + auto DDSynthesizer::decoder(TruthTable::CubeMap const& codewords, std::unique_ptr>& dd) -> void { const auto codeLength = codewords.begin()->second.size(); // decode the r most significant bits of the original output pattern. @@ -478,28 +478,31 @@ namespace syrec { } // Extend the dc in the inputs. - TruthTable newTT{}; for (auto const& [input, output]: ttCorrection) { auto completeInputs = input.completeCubes(); for (auto const& completeInput: completeInputs) { - newTT.try_emplace(completeInput, output); + ttCorrection.try_emplace(completeInput, output); } } - const auto ttCorrectionDD = buildDD(newTT, dd); + const auto ttCorrectionDD = buildDD(ttCorrection, dd); garbageFlag = true; - synthesize(ttCorrectionDD, dd, qc); + synthesize(ttCorrectionDD, dd); } // This function returns the operations required to synthesize the DD. - // flag -> If true, the synthesis is stopped after the nodeThreshold is reached. - // m -> No. of primary outputs. - auto DDSynthesizer::synthesize(dd::mEdge src, std::unique_ptr>& dd, const std::shared_ptr& qc) -> void { + auto DDSynthesizer::synthesize(dd::mEdge src, std::unique_ptr>& dd) -> std::shared_ptr { if (src.p == nullptr || src.p->isIdentity() || dcNodeCondition(src)) { - return; + return qc; } - // the threshold after which the outputs are considered to be garbage. + totalNoBits = static_cast(src.p->v + 1); + + if (!garbageFlag) { + qc = std::make_shared(totalNoBits); + } + + // The threshold after which the outputs are considered to be garbage. const auto garbageThreshold = static_cast(totalNoBits) - static_cast(m); // This following ensures that the `src` node resembles an identity structure. @@ -541,7 +544,7 @@ namespace syrec { dd->incRef(src); // perform the shifting paths algorithm. - const auto srcShifted = shiftingPaths(src, current, dd, qc); + const auto srcShifted = shiftingPaths(src, current, dd); const auto pathsShifted = (srcShifted != src); // decrement reference count of `src` node again and trigger garbage collection. @@ -570,45 +573,40 @@ namespace syrec { } } } - runtime = static_cast((std::chrono::steady_clock::now() - start).count()); + return qc; } - auto DDSynthesizer::synthesize(TruthTable const& tt) -> std::shared_ptr { + auto DDSynthesizer::synthesizeTT(TruthTable tt) -> std::shared_ptr { runtime = 0.; numGates = 0U; garbageFlag = false; - // no. of primary inputs. - const auto n = tt.nInputs(); - - TruthTable ttCpy(tt); + n = tt.nInputs(); + m = tt.nOutputs(); - extend(ttCpy); + extend(tt); // codewords -> Output patterns with the respective codewords. // k1 -> Minimum no. of additional lines required. - const auto [codewords, k1] = encodeHuffman(ttCpy); + const auto [codewords, k1] = encodeHuffman(tt); - totalNoBits = std::max(n, m + k1); - const auto r = totalNoBits - ttCpy.nOutputs(); + totalNoBits = std::max(n, m + k1); + r = totalNoBits - tt.nOutputs(); - augmentWithConstants(ttCpy, totalNoBits); + augmentWithConstants(tt, totalNoBits); - auto dd = std::make_unique>(totalNoBits); - const auto src = buildDD(ttCpy, dd); + ddSynth = std::make_unique>(totalNoBits); - // clear ttCpy as early as possible. - ttCpy.clear(); - const auto start = std::chrono::steady_clock::now(); + const auto src = buildDD(tt, ddSynth); - auto qc = std::make_shared(totalNoBits); - synthesize(src, dd, qc); + const auto start = std::chrono::steady_clock::now(); + synthesize(src, ddSynth); // if codeword is not empty, the above synthesized encoded function should be decoded. if (!codewords.empty()) { // synthesizing the corresponding decoder circuit. - decoder(codewords, r, dd, qc); + decoder(codewords, ddSynth); } runtime = static_cast((std::chrono::steady_clock::now() - start).count()); diff --git a/src/algorithms/synthesis/encoding.cpp b/src/algorithms/synthesis/encoding.cpp index 539f79bf..23815808 100644 --- a/src/algorithms/synthesis/encoding.cpp +++ b/src/algorithms/synthesis/encoding.cpp @@ -40,14 +40,6 @@ namespace syrec { } } - auto completeTruthTable(TruthTable& ttExpected, std::size_t const& totalNoBits) -> void { - extend(ttExpected); - for (auto& [input, output]: ttExpected) { - output.resize(totalNoBits); - } - augmentWithConstants(ttExpected, totalNoBits); - } - auto encodeHuffman(TruthTable& tt) -> std::pair { std::map outputFreq; for (const auto& [input, output]: tt) { @@ -56,7 +48,7 @@ namespace syrec { // if the truth table function is already reversible, no encoding is necessary if (outputFreq.size() == tt.size()) { - return {TruthTable::CubeMap{}, 0U}; + return {{}, 0U}; } // create a priority queue for building the Huffman tree @@ -137,15 +129,18 @@ namespace syrec { return {encoding, additionalLines}; } - auto augmentWithConstants(TruthTable& tt, std::size_t const& nBits) -> void { + auto augmentWithConstants(TruthTable& tt, std::size_t const& nBits, bool dc) -> void { const auto ancillaBits = nBits - tt.nOutputs(); for (auto& [input, output]: tt) { // add necessary constant inputs to the outputs based on the total number of bits (nBits). - for (auto i = 0U; i < ancillaBits; i++) { - output.insertZero(); + if (!dc) { + for (auto i = 0U; i < ancillaBits; i++) { + output.insertZero(); + } + } else { + output.resize(nBits); } - const auto inputSize = input.size(); const auto outputSize = output.size(); if (inputSize >= outputSize) { diff --git a/test/unittests/test_dd_synthesis.cpp b/test/unittests/test_dd_synthesis.cpp index 3bc5ba95..2a0e5558 100644 --- a/test/unittests/test_dd_synthesis.cpp +++ b/test/unittests/test_dd_synthesis.cpp @@ -60,14 +60,10 @@ TEST_P(TestDDSynth, GenericDDSynthesisTest) { const auto ttDD = buildDD(tt, dd); EXPECT_TRUE(ttDD.p != nullptr); - DDSynthesizer synthesizer(tt); - const auto totalNoBits = synthesizer.getNbits(); + DDSynthesizer synthesizer{}; - auto qc = std::make_shared(totalNoBits); - - synthesizer.synthesize(ttDD, dd, qc); - auto const* qcPtr = qc.get(); - const auto& qcDD = dd::buildFunctionality(qcPtr, dd); + const auto qc = synthesizer.synthesize(ttDD, dd); + const auto& qcDD = dd::buildFunctionality(qc.get(), dd); EXPECT_EQ(ttDD, qcDD); std::cout << synthesizer.numGate() << "\n"; diff --git a/test/unittests/test_dd_synthesis_dc.cpp b/test/unittests/test_dd_synthesis_dc.cpp index cbe19894..8f7eb0bf 100644 --- a/test/unittests/test_dd_synthesis_dc.cpp +++ b/test/unittests/test_dd_synthesis_dc.cpp @@ -11,7 +11,6 @@ using namespace syrec; class TestDDSynthDc: public testing::TestWithParam { protected: TruthTable tt{}; - TruthTable ttExpected{}; TruthTable ttqc{}; std::string testCircuitsDir = "./circuits/"; std::string fileName; @@ -60,19 +59,16 @@ INSTANTIATE_TEST_SUITE_P(TestDDSynth, TestDDSynthDc, TEST_P(TestDDSynthDc, GenericDDSynthesisDcTest) { EXPECT_TRUE(readPla(tt, fileName)); - DDSynthesizer synthesizer(tt); - const auto& qc = synthesizer.synthesize(tt); - const auto totalNoBits = synthesizer.getNbits(); - auto const* qcPtr = qc.get(); + const auto& qc = DDSynthesizer::synthesize(tt); + const auto totalNoBits = qc->getNqubits(); // generate the complete truth table. - TruthTable ttExpected{tt}; - completeTruthTable(ttExpected, totalNoBits); + extend(tt); + augmentWithConstants(tt, totalNoBits, true); - buildTruthTable(qcPtr, ttqc); + buildTruthTable(*qc, ttqc); - EXPECT_TRUE(TruthTable::equal(ttExpected, ttqc)); + EXPECT_TRUE(TruthTable::equal(tt, ttqc)); - std::cout << synthesizer.numGate() << "\n"; - std::cout << synthesizer.getExecutionTime() << "\n"; + std::cout << qc->getNops() << "\n"; } From 1749fa631e63652bfa41c7ef3cef63b3ac630cb0 Mon Sep 17 00:00:00 2001 From: SmaranTum Date: Tue, 6 Dec 2022 01:28:49 +0100 Subject: [PATCH 5/6] Removed the assertion error. --- src/algorithms/synthesis/dd_synthesis.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/algorithms/synthesis/dd_synthesis.cpp b/src/algorithms/synthesis/dd_synthesis.cpp index b8a95182..a6e7db59 100644 --- a/src/algorithms/synthesis/dd_synthesis.cpp +++ b/src/algorithms/synthesis/dd_synthesis.cpp @@ -474,14 +474,11 @@ namespace syrec { for (auto i = 0U; i < codeLength; i++) { inCube.emplace_back(code[i]); } - ttCorrection.try_emplace(inCube, outCube); - } - // Extend the dc in the inputs. - for (auto const& [input, output]: ttCorrection) { - auto completeInputs = input.completeCubes(); + // Extend the dc in the inputs. + const auto completeInputs = inCube.completeCubes(); for (auto const& completeInput: completeInputs) { - ttCorrection.try_emplace(completeInput, output); + ttCorrection.try_emplace(completeInput, outCube); } } From 5629005dd7c0abf16d350166c267db8ec114ffe8 Mon Sep 17 00:00:00 2001 From: SmaranTum Date: Tue, 6 Dec 2022 19:55:48 +0100 Subject: [PATCH 6/6] Changes based on review comments. --- include/algorithms/synthesis/dd_synthesis.hpp | 2 +- src/algorithms/synthesis/dd_synthesis.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/algorithms/synthesis/dd_synthesis.hpp b/include/algorithms/synthesis/dd_synthesis.hpp index 3cbf0ddc..2198d42e 100644 --- a/include/algorithms/synthesis/dd_synthesis.hpp +++ b/include/algorithms/synthesis/dd_synthesis.hpp @@ -70,7 +70,7 @@ namespace syrec { auto unifyPath(dd::mEdge src, dd::mEdge const& current, TruthTable::Cube::Set const& p1SigVec, TruthTable::Cube::Set const& p2SigVec, bool const& changePaths, std::unique_ptr>& dd) -> dd::mEdge; auto shiftingPaths(dd::mEdge const& src, dd::mEdge const& current, std::unique_ptr>& dd) -> dd::mEdge; - auto decoder(TruthTable::CubeMap const& codewords, std::unique_ptr>& dd) -> void; + auto decoder(TruthTable::CubeMap const& codewords) -> void; auto synthesizeTT(TruthTable tt) -> std::shared_ptr; }; diff --git a/src/algorithms/synthesis/dd_synthesis.cpp b/src/algorithms/synthesis/dd_synthesis.cpp index a6e7db59..a2322781 100644 --- a/src/algorithms/synthesis/dd_synthesis.cpp +++ b/src/algorithms/synthesis/dd_synthesis.cpp @@ -429,7 +429,7 @@ namespace syrec { } // Refer to the decoder algorithm of https://www.cda.cit.tum.de/files/eda/2018_aspdac_coding_techniques_in_synthesis.pdf. - auto DDSynthesizer::decoder(TruthTable::CubeMap const& codewords, std::unique_ptr>& dd) -> void { + auto DDSynthesizer::decoder(TruthTable::CubeMap const& codewords) -> void { const auto codeLength = codewords.begin()->second.size(); // decode the r most significant bits of the original output pattern. @@ -482,9 +482,9 @@ namespace syrec { } } - const auto ttCorrectionDD = buildDD(ttCorrection, dd); + const auto ttCorrectionDD = buildDD(ttCorrection, ddSynth); garbageFlag = true; - synthesize(ttCorrectionDD, dd); + synthesize(ttCorrectionDD, ddSynth); } // This function returns the operations required to synthesize the DD. @@ -603,7 +603,7 @@ namespace syrec { // if codeword is not empty, the above synthesized encoded function should be decoded. if (!codewords.empty()) { // synthesizing the corresponding decoder circuit. - decoder(codewords, ddSynth); + decoder(codewords); } runtime = static_cast((std::chrono::steady_clock::now() - start).count());