diff --git a/include/algorithms/simulation/simple_simulation.hpp b/include/algorithms/simulation/simple_simulation.hpp index 5a75eef4..6e479df9 100644 --- a/include/algorithms/simulation/simple_simulation.hpp +++ b/include/algorithms/simulation/simple_simulation.hpp @@ -60,6 +60,6 @@ namespace syrec { * */ void simpleSimulation(boost::dynamic_bitset<>& output, const Circuit& circ, const boost::dynamic_bitset<>& input, - const Properties::ptr& statistics = Properties::ptr()); + const Properties::ptr& statistics = Properties::ptr(), const bool reverse = false); } // namespace syrec diff --git a/include/core/circuit.hpp b/include/core/circuit.hpp index b265864a..effe2dca 100644 --- a/include/core/circuit.hpp +++ b/include/core/circuit.hpp @@ -95,6 +95,15 @@ namespace syrec { return gates.cbegin(); } + /** + * @brief Constant reverse begin iterator pointing to gates + * + * @return Constant reverse begin iterator + */ + [[nodiscard]] auto crbegin() const { + return gates.crbegin(); + } + /** * @brief Begin iterator pointing to gates * @@ -113,6 +122,15 @@ namespace syrec { return gates.cend(); } + /** + * @brief Constant reverse end iterator pointing to gates + * + * @return Constant reverse end iterator + */ + [[nodiscard]] auto crend() const { + return gates.crend(); + } + /** * @brief End iterator pointing to gates * diff --git a/src/algorithms/simulation/simple_simulation.cpp b/src/algorithms/simulation/simple_simulation.cpp index 88bf7dc7..8cf3878e 100644 --- a/src/algorithms/simulation/simple_simulation.cpp +++ b/src/algorithms/simulation/simple_simulation.cpp @@ -58,7 +58,7 @@ namespace syrec { } void simpleSimulation(boost::dynamic_bitset<>& output, const Circuit& circ, const boost::dynamic_bitset<>& input, - const Properties::ptr& statistics) { + const Properties::ptr& statistics, const bool reverse) { Timer t; if (statistics) { @@ -67,8 +67,14 @@ namespace syrec { } output = input; - for (const auto& g: circ) { - coreGateSimulation(*g, output); + if (reverse) { + for (auto g = circ.crbegin(); g != circ.crend(); ++g) { + coreGateSimulation(*(*g), output); + } + } else { + for (const auto& g: circ) { + coreGateSimulation(*g, output); + } } if (statistics) { diff --git a/src/python/bindings.cpp b/src/python/bindings.cpp index 9ccc439f..4747f669 100644 --- a/src/python/bindings.cpp +++ b/src/python/bindings.cpp @@ -100,5 +100,5 @@ PYBIND11_MODULE(pysyrec, m) { m.def("cost_aware_synthesis", &CostAwareSynthesis::synthesize, "circ"_a, "program"_a, "settings"_a = Properties::ptr(), "statistics"_a = Properties::ptr(), "Cost-aware synthesis of the SyReC program."); m.def("line_aware_synthesis", &LineAwareSynthesis::synthesize, "circ"_a, "program"_a, "settings"_a = Properties::ptr(), "statistics"_a = Properties::ptr(), "Line-aware synthesis of the SyReC program."); - m.def("simple_simulation", &simpleSimulation, "output"_a, "circ"_a, "input"_a, "statistics"_a = Properties::ptr(), "Simulation of the synthesized circuit circ."); + m.def("simple_simulation", &simpleSimulation, "output"_a, "circ"_a, "input"_a, "statistics"_a = Properties::ptr(), "reverse"_a = false, "Simulation of the synthesized circuit circ."); } diff --git a/test/python/test_syrec.py b/test/python/test_syrec.py index fa8eb29b..f581f26b 100644 --- a/test/python/test_syrec.py +++ b/test/python/test_syrec.py @@ -92,6 +92,7 @@ def test_simulation_no_lines(data_line_aware_simulation: dict[str, Any]) -> None my_inp_bitset = syrec.bitset(circ.lines) my_out_bitset = syrec.bitset(circ.lines) + my_out_bitset2 = syrec.bitset(circ.lines) set_list = data_line_aware_simulation[file_name]["set_lines"] for set_index in set_list: @@ -100,6 +101,10 @@ def test_simulation_no_lines(data_line_aware_simulation: dict[str, Any]) -> None syrec.simple_simulation(my_out_bitset, circ, my_inp_bitset) assert data_line_aware_simulation[file_name]["sim_out"] == str(my_out_bitset) + # Check reversed simulation + syrec.simple_simulation(my_out_bitset2, circ, my_out_bitset, reverse=True) + assert str(my_out_bitset2) == str(my_inp_bitset) + def test_simulation_add_lines(data_cost_aware_simulation: dict[str, Any]) -> None: for file_name in data_cost_aware_simulation: @@ -112,6 +117,7 @@ def test_simulation_add_lines(data_cost_aware_simulation: dict[str, Any]) -> Non my_inp_bitset = syrec.bitset(circ.lines) my_out_bitset = syrec.bitset(circ.lines) + my_out_bitset2 = syrec.bitset(circ.lines) set_list = data_cost_aware_simulation[file_name]["set_lines"] for set_index in set_list: @@ -120,6 +126,10 @@ def test_simulation_add_lines(data_cost_aware_simulation: dict[str, Any]) -> Non syrec.simple_simulation(my_out_bitset, circ, my_inp_bitset) assert data_cost_aware_simulation[file_name]["sim_out"] == str(my_out_bitset) + # Check reversed simulation + syrec.simple_simulation(my_out_bitset2, circ, my_out_bitset, reverse=True) + assert str(my_out_bitset2) == str(my_inp_bitset) + def test_no_lines_to_qasm(data_line_aware_synthesis: dict[str, Any]) -> None: for file_name in data_line_aware_synthesis: diff --git a/test/unittests/test_cost_aware_simulation.cpp b/test/unittests/test_cost_aware_simulation.cpp index 0bcf4cf4..e349eceb 100644 --- a/test/unittests/test_cost_aware_simulation.cpp +++ b/test/unittests/test_cost_aware_simulation.cpp @@ -31,9 +31,9 @@ class SyrecAddLinesSimulationTest: public testing::TestWithParam { std::string testCircuitsDir = "./circuits/"; std::string fileName; boost::dynamic_bitset<> input; - boost::dynamic_bitset<> output; + boost::dynamic_bitset<> output, output2; std::vector setLines; - std::string expectedSimOut; + std::string expectedSimOut, expectedSimIn; std::string outputString; void SetUp() override { @@ -78,6 +78,7 @@ TEST_P(SyrecAddLinesSimulationTest, GenericSimulationTest) { } output.resize(circ.getLines()); + output2.resize(circ.getLines()); simpleSimulation(output, circ, input, statistics); @@ -85,4 +86,10 @@ TEST_P(SyrecAddLinesSimulationTest, GenericSimulationTest) { std::reverse(outputString.begin(), outputString.end()); EXPECT_EQ(expectedSimOut, outputString); + + // Check reversed simulation + simpleSimulation(output2, circ, output, statistics, true); + boost::to_string(output2, outputString); + boost::to_string(input, expectedSimIn); + EXPECT_EQ(expectedSimIn, outputString); } diff --git a/test/unittests/test_line_aware_simulation.cpp b/test/unittests/test_line_aware_simulation.cpp index 746ac8a3..c1beb8bc 100644 --- a/test/unittests/test_line_aware_simulation.cpp +++ b/test/unittests/test_line_aware_simulation.cpp @@ -31,9 +31,9 @@ class SyrecSimulationTest: public testing::TestWithParam { std::string testCircuitsDir = "./circuits/"; std::string fileName; boost::dynamic_bitset<> input; - boost::dynamic_bitset<> output; + boost::dynamic_bitset<> output, output2; std::vector setLines; - std::string expectedSimOut; + std::string expectedSimOut, expectedSimIn; std::string outputString; void SetUp() override { @@ -78,6 +78,7 @@ TEST_P(SyrecSimulationTest, GenericSimulationTest) { } output.resize(circ.getLines()); + output2.resize(circ.getLines()); simpleSimulation(output, circ, input, statistics); @@ -85,4 +86,10 @@ TEST_P(SyrecSimulationTest, GenericSimulationTest) { std::reverse(outputString.begin(), outputString.end()); EXPECT_EQ(expectedSimOut, outputString); + + // Check reversed simulation + simpleSimulation(output2, circ, output, statistics, true); + boost::to_string(output2, outputString); + boost::to_string(input, expectedSimIn); + EXPECT_EQ(expectedSimIn, outputString); }