diff --git a/include/algorithms/simulation/simple_simulation.hpp b/include/algorithms/simulation/simple_simulation.hpp index fc33e465..a3fecf57 100644 --- a/include/algorithms/simulation/simple_simulation.hpp +++ b/include/algorithms/simulation/simple_simulation.hpp @@ -1,11 +1,4 @@ -/** -* @file simple_simulation.hpp -* -* @brief Very simple simulation, only efficient for small circuits -*/ - -#ifndef SIMPLE_SIMULATION_HPP -#define SIMPLE_SIMULATION_HPP +#pragma once #include "core/circuit.hpp" #include "core/properties.hpp" @@ -60,5 +53,3 @@ namespace syrec { const properties::ptr& statistics = properties::ptr()); } // namespace syrec - -#endif /* SIMPLE_SIMULATION_HPP */ diff --git a/include/algorithms/synthesis/syrec_synthesis.hpp b/include/algorithms/synthesis/syrec_synthesis.hpp index 08ff0390..bdad83fe 100644 --- a/include/algorithms/synthesis/syrec_synthesis.hpp +++ b/include/algorithms/synthesis/syrec_synthesis.hpp @@ -1,11 +1,4 @@ -/** -* @file syrec_synthesis.hpp -* -* @brief SyReC Synthesis -*/ - -#ifndef SYREC_SYNTHESIS_HPP -#define SYREC_SYNTHESIS_HPP +#pragma once #include "core/circuit.hpp" #include "core/gate.hpp" @@ -28,11 +21,8 @@ namespace syrec::internal { std::shared_ptr circ; }; - typedef boost::adjacency_list> - cct; - - typedef boost::graph_traits::vertex_descriptor cct_node; + using cct = boost::adjacency_list>; + using cct_node = boost::graph_traits::vertex_descriptor; struct cct_manager { cct tree; @@ -44,115 +34,118 @@ namespace syrec::internal { namespace syrec { using namespace internal; - class standard_syrec_synthesizer { + class SyrecSynthesis { public: std::stack exp_opp; - std::stack> exp_lhss, exp_rhss; + std::stack> exp_lhss; + std::stack> exp_rhss; bool sub_flag = false; - std::vector op_vec, assign_op_vector, exp_op_vector; - std::vector> exp_lhs_vector, exp_rhs_vector; + std::vector op_vec; + std::vector assign_op_vector; + std::vector exp_op_vector; + std::vector> exp_lhs_vector; + std::vector> exp_rhs_vector; - typedef std::map var_lines_map; + using var_lines_map = std::map; - standard_syrec_synthesizer(circuit& circ, const program& prog); + explicit SyrecSynthesis(circuit& circ); + virtual ~SyrecSynthesis() = default; - virtual ~standard_syrec_synthesizer() = default; + void add_variables(circuit& circ, const variable::vec& variables); + void set_main_module(const module::ptr& main_module); + + protected: + // TODO: please find a proper name for this function, this is just a placeholder for now + virtual bool process_statement(const statement::ptr& statement) = 0; - virtual void add_variables(circuit& circ, const variable::vec& variables); virtual bool on_module(const module::ptr&); - virtual bool on_statement(const statement::ptr& statement); - virtual bool on_expression(const expression::ptr& expression, std::vector& lines, std::vector& lhs_stat, unsigned op); - virtual bool op_rhs_lhs_expression(const expression::ptr& expression, std::vector& v); - virtual bool full_statement(const statement::ptr& statement); - virtual bool flow(const expression::ptr& expression, std::vector& v); - virtual void set_main_module(const module::ptr& main_module); - virtual bool solver(const std::vector& stat_lhs, unsigned stat_op, const std::vector& exp_lhs, unsigned exp_op, const std::vector& exp_rhs); - protected: - virtual bool on_statement(const swap_statement& statement); - virtual bool on_statement(const unary_statement& statement); - virtual bool on_statement(const assign_statement& statement); - virtual bool on_statement(const if_statement& statement); - virtual bool on_statement(const for_statement& statement); - virtual bool on_statement(const call_statement& statement); - virtual bool on_statement(const uncall_statement& statement); - virtual bool on_statement(const skip_statement& statement); - virtual bool op_rhs_lhs_expression(const variable_expression& expression, std::vector& v); - virtual bool op_rhs_lhs_expression(const binary_expression& expression, std::vector& v); - virtual bool full_statement(const assign_statement& statement); - - // expressions + virtual bool op_rhs_lhs_expression([[maybe_unused]] const expression::ptr& expression, [[maybe_unused]] std::vector& v); + virtual bool op_rhs_lhs_expression([[maybe_unused]] const variable_expression& expression, [[maybe_unused]] std::vector& v); + virtual bool op_rhs_lhs_expression([[maybe_unused]] const binary_expression& expression, [[maybe_unused]] std::vector& v); + + virtual bool on_statement(const statement::ptr& statement); + virtual bool on_statement(const assign_statement& statement); + virtual bool on_statement(const if_statement& statement); + virtual bool on_statement(const for_statement& statement); + virtual bool on_statement(const call_statement& statement); + virtual bool on_statement(const uncall_statement& statement); + bool on_statement(const swap_statement& statement); + bool on_statement(const unary_statement& statement); + [[nodiscard]] static bool on_statement(const skip_statement& statement); + + virtual void assign_add(bool& status, std::vector& lhs, std::vector& rhs, [[maybe_unused]] const unsigned& op) = 0; + + virtual void assign_subtract(bool& status, std::vector& lhs, std::vector& rhs, [[maybe_unused]] const unsigned& op) = 0; + virtual void assign_exor(bool& status, std::vector& lhs, std::vector& rhs, [[maybe_unused]] const unsigned& op) = 0; + + virtual bool on_expression(const expression::ptr& expression, std::vector& lines, std::vector const& lhs_stat, unsigned op); + virtual bool on_expression(const binary_expression& expression, std::vector& lines, std::vector const& lhs_stat, unsigned op); + virtual bool on_expression(const shift_expression& expression, std::vector& lines, std::vector const& lhs_stat, unsigned op); virtual bool on_expression(const numeric_expression& expression, std::vector& lines); virtual bool on_expression(const variable_expression& expression, std::vector& lines); - virtual bool on_expression(const binary_expression& expression, std::vector& lines, std::vector& lhs_stat, unsigned op); - virtual bool on_expression(const shift_expression& expression, std::vector& lines, std::vector& lhs_stat, unsigned op); - virtual bool flow(const variable_expression& expression, std::vector& v); - virtual bool flow(const binary_expression& expression, std::vector& v); + virtual void exp_add([[maybe_unused]] const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) = 0; + + virtual void exp_subtract([[maybe_unused]] const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) = 0; + + virtual void exp_exor([[maybe_unused]] const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) = 0; // unary operations - virtual bool bitwise_negation(const std::vector& dest); // ~ - virtual bool decrement(const std::vector& dest); // -- - virtual bool increment(const std::vector& dest); // ++ + bool bitwise_negation(const std::vector& dest); // ~ + bool decrement(const std::vector& dest); // -- + bool increment(const std::vector& dest); // ++ // binary operations - virtual bool bitwise_and(const std::vector& dest, const std::vector& src1, const std::vector& src2); // & - virtual bool bitwise_cnot(const std::vector& dest, const std::vector& src); // ^= - virtual bool bitwise_or(const std::vector& dest, const std::vector& src1, const std::vector& src2); // & - virtual bool conjunction(unsigned dest, unsigned src1, unsigned src2); // &&// -= - virtual bool decrease_with_carry(const std::vector& dest, const std::vector& src, unsigned carry); - virtual bool disjunction(unsigned dest, unsigned src1, unsigned src2); // || - virtual bool division(const std::vector& dest, const std::vector& src1, const std::vector& src2); // / - virtual bool equals(unsigned dest, const std::vector& src1, const std::vector& src2); // = - virtual bool greater_equals(unsigned dest, const std::vector& src1, const std::vector& src2); // > - virtual bool greater_than(unsigned dest, const std::vector& src1, const std::vector& src2); // >// += - virtual bool increase_with_carry(const std::vector& dest, const std::vector& src, unsigned carry); - virtual bool less_equals(unsigned dest, const std::vector& src1, const std::vector& src2); // <= - virtual bool less_than(unsigned dest, const std::vector& src1, const std::vector& src2); // < - virtual bool modulo(const std::vector& dest, const std::vector& src1, const std::vector& src2); // % - virtual bool multiplication(const std::vector& dest, const std::vector& src1, const std::vector& src2); // * - virtual bool not_equals(unsigned dest, const std::vector& src1, const std::vector& src2); // != - virtual void swap(const std::vector& dest1, const std::vector& dest2); // <=> - virtual bool check_repeats(); - - virtual bool decrease_new(const std::vector& rhs, const std::vector& lhs); - virtual bool decrease_new_assign(const std::vector& rhs, const std::vector& lhs); - virtual bool increase_new(const std::vector& rhs, const std::vector& lhs); - virtual bool expression_op_inverse(unsigned op, const std::vector& exp_lhs, const std::vector& exp_rhs); - virtual bool expression_single_op(unsigned op, const std::vector& exp_lhs, const std::vector& exp_rhs); - virtual bool exp_evaluate(std::vector& lines, unsigned op, const std::vector& lhs, const std::vector& rhs); + bool bitwise_and(const std::vector& dest, const std::vector& src1, const std::vector& src2); // & + bool bitwise_cnot(const std::vector& dest, const std::vector& src); // ^= + bool bitwise_or(const std::vector& dest, const std::vector& src1, const std::vector& src2); // & + bool conjunction(unsigned dest, unsigned src1, unsigned src2); // &&// -= + bool decrease_with_carry(const std::vector& dest, const std::vector& src, unsigned carry); + bool disjunction(unsigned dest, unsigned src1, unsigned src2); // || + bool division(const std::vector& dest, const std::vector& src1, const std::vector& src2); // / + bool equals(unsigned dest, const std::vector& src1, const std::vector& src2); // = + bool greater_equals(unsigned dest, const std::vector& src1, const std::vector& src2); // > + bool greater_than(unsigned dest, const std::vector& src1, const std::vector& src2); // >// += + bool increase_with_carry(const std::vector& dest, const std::vector& src, unsigned carry); + bool less_equals(unsigned dest, const std::vector& src1, const std::vector& src2); // <= + bool less_than(unsigned dest, const std::vector& src1, const std::vector& src2); // < + bool modulo(const std::vector& dest, const std::vector& src1, const std::vector& src2); // % + bool multiplication(const std::vector& dest, const std::vector& src1, const std::vector& src2); // * + bool not_equals(unsigned dest, const std::vector& src1, const std::vector& src2); // != + void swap(const std::vector& dest1, const std::vector& dest2); // <=> + bool decrease(const std::vector& rhs, const std::vector& lhs); + bool increase(const std::vector& rhs, const std::vector& lhs); + virtual bool expression_op_inverse([[maybe_unused]] unsigned op, [[maybe_unused]] const std::vector& exp_lhs, [[maybe_unused]] const std::vector& exp_rhs); + bool check_repeats(); + // shift operations - virtual void left_shift(const std::vector& dest, const std::vector& src1, unsigned src2); // << - virtual void right_shift(const std::vector& dest, const std::vector& src1, unsigned src2); // >> + void left_shift(const std::vector& dest, const std::vector& src1, unsigned src2); // << + void right_shift(const std::vector& dest, const std::vector& src1, unsigned src2); // >> - // efficient controls - virtual void add_active_control(unsigned); - virtual void remove_active_control(unsigned); + void add_active_control(unsigned); + void remove_active_control(unsigned); - virtual bool assemble_circuit(const cct_node&); + bool assemble_circuit(const cct_node&); cct_manager cct_man; - virtual void add_variable(circuit& circ, const std::vector& dimensions, const variable::ptr& var, constant _constant, bool _garbage, const std::string& arraystr); - virtual void get_variables(const variable_access::ptr& var, std::vector& lines); + void add_variable(circuit& circ, const std::vector& dimensions, const variable::ptr& var, constant _constant, bool _garbage, const std::string& arraystr); + void get_variables(const variable_access::ptr& var, std::vector& lines); - virtual unsigned get_constant_line(bool value); - virtual void get_constant_lines(unsigned bitwidth, unsigned value, std::vector& lines); + unsigned get_constant_line(bool value); + void get_constant_lines(unsigned bitwidth, unsigned value, std::vector& lines); + + static bool synthesize(SyrecSynthesis* synthesizer, circuit& circ, const program& program, const properties::ptr& settings, const properties::ptr& statistics); + + std::stack _stmts; + circuit& _circ; + number::loop_variable_mapping loop_map; + std::stack modules; private: - circuit& _circ; - std::stack _stmts; var_lines_map _var_lines; std::map> free_const_lines_map; - number::loop_variable_mapping loop_map; - - std::stack modules; }; - /** - * @brief SyReC Synthesis - */ - bool syrec_synthesis(circuit& circ, const program& program, const properties::ptr& settings = std::make_shared(), const properties::ptr& statistics = std::make_shared()); } // namespace syrec - -#endif /* SYREC_SYNTHESIS_HPP */ diff --git a/include/algorithms/synthesis/syrec_synthesis_additional_lines.hpp b/include/algorithms/synthesis/syrec_synthesis_additional_lines.hpp new file mode 100644 index 00000000..2478f8f7 --- /dev/null +++ b/include/algorithms/synthesis/syrec_synthesis_additional_lines.hpp @@ -0,0 +1,34 @@ +#pragma once + +#include "algorithms/synthesis/syrec_synthesis.hpp" + +namespace syrec { + class SyrecSynthesisAdditionalLines: public SyrecSynthesis { + public: + using SyrecSynthesis::SyrecSynthesis; + + static bool synthesize(circuit& circ, const program& program, const properties::ptr& settings = std::make_shared(), const properties::ptr& statistics = std::make_shared()); + + protected: + bool process_statement(const statement::ptr& statement) override { + return !SyrecSynthesis::on_statement(statement); + } + + void assign_add(bool& status, std::vector& lhs, std::vector& rhs, [[maybe_unused]] const unsigned& op) override { + status = SyrecSynthesis::increase(lhs, rhs); + } + + void assign_subtract(bool& status, std::vector& lhs, std::vector& rhs, [[maybe_unused]] const unsigned& op) override { + status = SyrecSynthesis::decrease(lhs, rhs); + } + + void assign_exor(bool& status, std::vector& lhs, std::vector& rhs, [[maybe_unused]] const unsigned& op) override { + status = SyrecSynthesis::bitwise_cnot(lhs, rhs); + } + + void exp_add(const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) override; + void exp_subtract(const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) override; + + void exp_exor(const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) override; + }; +} // namespace syrec diff --git a/include/algorithms/synthesis/syrec_synthesis_no_additional_lines.hpp b/include/algorithms/synthesis/syrec_synthesis_no_additional_lines.hpp new file mode 100644 index 00000000..c1c3d6f9 --- /dev/null +++ b/include/algorithms/synthesis/syrec_synthesis_no_additional_lines.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "algorithms/synthesis/syrec_synthesis.hpp" + +namespace syrec { + class SyrecSynthesisNoAdditionalLines: public SyrecSynthesis { + public: + using SyrecSynthesis::SyrecSynthesis; + + static bool synthesize(circuit& circ, const program& program, const properties::ptr& settings = std::make_shared(), const properties::ptr& statistics = std::make_shared()); + + protected: + bool process_statement(const statement::ptr& statement) override { + return !full_statement(statement) && !SyrecSynthesis::on_statement(statement); + } + + bool full_statement(const statement::ptr& statement); + bool full_statement(const assign_statement& statement); + + bool op_rhs_lhs_expression(const expression::ptr& expression, std::vector& v) override; + + bool op_rhs_lhs_expression(const variable_expression& expression, std::vector& v) override; + + bool op_rhs_lhs_expression(const binary_expression& expression, std::vector& v) override; + + void pop_exp(); + + void inverse(); + + void assign_add(bool& status, std::vector& lhs, std::vector& rhs, const unsigned& op) override; + + void assign_subtract(bool& status, std::vector& lhs, std::vector& rhs, const unsigned& op) override; + + void assign_exor(bool& status, std::vector& lhs, std::vector& rhs, const unsigned& op) override; + + bool solver(const std::vector& stat_lhs, unsigned stat_op, const std::vector& exp_lhs, unsigned exp_op, const std::vector& exp_rhs); + + bool flow(const expression::ptr& expression, std::vector& v); + bool flow(const variable_expression& expression, std::vector& v); + bool flow(const binary_expression& expression, const std::vector& v); + + void exp_add([[maybe_unused]] const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) override { + SyrecSynthesis::increase(rhs, lhs); + lines = rhs; + } + + void exp_subtract([[maybe_unused]] const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) override { + decrease_new_assign(rhs, lhs); + lines = rhs; + } + + void exp_exor([[maybe_unused]] const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) override { + bitwise_cnot(rhs, lhs); // duplicate lhs + lines = rhs; + } + + bool exp_evaluate(std::vector& lines, unsigned op, const std::vector& lhs, const std::vector& rhs); + + bool expression_single_op(unsigned op, const std::vector& exp_lhs, const std::vector& exp_rhs); + + bool decrease_new_assign(const std::vector& rhs, const std::vector& lhs); + + bool expression_op_inverse(unsigned op, const std::vector& exp_lhs, const std::vector& exp_rhs) override; + }; +} // namespace syrec diff --git a/include/core/circuit.hpp b/include/core/circuit.hpp index a87b6713..e23a636c 100644 --- a/include/core/circuit.hpp +++ b/include/core/circuit.hpp @@ -1,11 +1,4 @@ -/** - * @file circuit.hpp - * - * @brief Circuit class - */ - -#ifndef CIRCUIT_HPP -#define CIRCUIT_HPP +#pragma once #include "core/gate.hpp" @@ -501,5 +494,3 @@ namespace syrec { }; } // namespace syrec - -#endif /* CIRCUIT_HPP */ diff --git a/include/core/gate.hpp b/include/core/gate.hpp index 84f31c45..3f841dcc 100644 --- a/include/core/gate.hpp +++ b/include/core/gate.hpp @@ -1,11 +1,4 @@ -/** - * @file gate.hpp - * - * @brief Gate class - */ - -#ifndef GATE_HPP -#define GATE_HPP +#pragma once #include #include @@ -118,5 +111,3 @@ namespace syrec { }; } // namespace syrec - -#endif /* GATE_HPP */ diff --git a/include/core/properties.hpp b/include/core/properties.hpp index f7678fa6..ab3b7f26 100644 --- a/include/core/properties.hpp +++ b/include/core/properties.hpp @@ -1,11 +1,4 @@ -/** - * @file properties.hpp - * - * @brief Property Map Implementation for Algorithms - */ - -#ifndef PROPERTIES_HPP -#define PROPERTIES_HPP +#pragma once #include #include @@ -148,5 +141,3 @@ namespace syrec { } } // namespace syrec - -#endif /* PROPERTIES_HPP */ diff --git a/include/core/syrec/expression.hpp b/include/core/syrec/expression.hpp index b2aff417..a6f6af21 100644 --- a/include/core/syrec/expression.hpp +++ b/include/core/syrec/expression.hpp @@ -1,10 +1,4 @@ -/** - * @file expression.hpp - * - * @brief SyReC expression data types - */ -#ifndef EXPRESSION_HPP -#define EXPRESSION_HPP +#pragma once #include "core/syrec/variable.hpp" @@ -347,5 +341,3 @@ namespace syrec { }; } // namespace syrec - -#endif /* EXPRESSION_HPP */ diff --git a/include/core/syrec/grammar.hpp b/include/core/syrec/grammar.hpp index 9b0d9b38..d2676be7 100644 --- a/include/core/syrec/grammar.hpp +++ b/include/core/syrec/grammar.hpp @@ -1,5 +1,4 @@ -#ifndef GRAMMAR_HPP -#define GRAMMAR_HPP +#pragma once #include #include @@ -315,5 +314,3 @@ namespace syrec { class program; } // namespace syrec - -#endif /* GRAMMAR_HPP */ diff --git a/include/core/syrec/module.hpp b/include/core/syrec/module.hpp index 5ce9099c..c3e6f577 100644 --- a/include/core/syrec/module.hpp +++ b/include/core/syrec/module.hpp @@ -1,10 +1,4 @@ -/** - * @file module.hpp - * - * @brief SyReC module data type - */ -#ifndef MODULE_HPP -#define MODULE_HPP +#pragma once #include "core/syrec/statement.hpp" #include "core/syrec/variable.hpp" @@ -89,5 +83,3 @@ namespace syrec { }; } // namespace syrec - -#endif /* MODULE_HPP */ diff --git a/include/core/syrec/number.hpp b/include/core/syrec/number.hpp index b048afe2..4152a592 100644 --- a/include/core/syrec/number.hpp +++ b/include/core/syrec/number.hpp @@ -1,10 +1,4 @@ -/** - * @file number.hpp - * - * @brief SyReC number data type - */ -#ifndef NUMBER_HPP -#define NUMBER_HPP +#pragma once #include #include @@ -63,5 +57,3 @@ namespace syrec { }; } // namespace syrec - -#endif /* NUMBER_HPP */ diff --git a/include/core/syrec/parser.hpp b/include/core/syrec/parser.hpp index 5b5c0e51..7a46691c 100644 --- a/include/core/syrec/parser.hpp +++ b/include/core/syrec/parser.hpp @@ -1,10 +1,4 @@ -/** -* @file parser.hpp -* -* @brief SyReC parser routines -*/ -#ifndef PARSER_HPP -#define PARSER_HPP +#pragma once #include "core/syrec/expression.hpp" #include "core/syrec/grammar.hpp" @@ -43,5 +37,3 @@ namespace syrec { variable_access::ptr parse_variable_access(const ast_variable& ast_var, const module& proc, parser_context& context); } // namespace syrec - -#endif /* PARSER_HPP */ diff --git a/include/core/syrec/program.hpp b/include/core/syrec/program.hpp index 109c07cb..fdc8a15a 100644 --- a/include/core/syrec/program.hpp +++ b/include/core/syrec/program.hpp @@ -1,10 +1,4 @@ -/** - * @file program.hpp - * - * @brief SyReC program - */ -#ifndef PROGRAM_HPP -#define PROGRAM_HPP +#pragma once #include "core/syrec/expression.hpp" #include "core/syrec/grammar.hpp" @@ -70,5 +64,3 @@ namespace syrec { }; } // namespace syrec - -#endif /* PROGRAM_HPP */ diff --git a/include/core/syrec/statement.hpp b/include/core/syrec/statement.hpp index e90191be..a3e178b9 100644 --- a/include/core/syrec/statement.hpp +++ b/include/core/syrec/statement.hpp @@ -1,10 +1,4 @@ -/** - * @file statement.hpp - * - * @brief SyReC statement data types - */ -#ifndef STATEMENT_HPP -#define STATEMENT_HPP +#pragma once #include "core/syrec/expression.hpp" #include "core/syrec/module.hpp" @@ -358,5 +352,3 @@ namespace syrec { } } // namespace syrec - -#endif /* STATEMENT_HPP */ diff --git a/include/core/syrec/variable.hpp b/include/core/syrec/variable.hpp index 1b1a1c07..76cb2a9b 100644 --- a/include/core/syrec/variable.hpp +++ b/include/core/syrec/variable.hpp @@ -1,10 +1,4 @@ -/** - * @file variable.hpp - * - * @brief SyReC variable data type - */ -#ifndef VARIABLE_HPP -#define VARIABLE_HPP +#pragma once #include "core/syrec/number.hpp" @@ -124,5 +118,3 @@ namespace syrec { }; } // namespace syrec - -#endif /* VARIABLE_HPP */ diff --git a/include/core/utils/timer.hpp b/include/core/utils/timer.hpp index c3a92f11..71b22790 100644 --- a/include/core/utils/timer.hpp +++ b/include/core/utils/timer.hpp @@ -1,11 +1,4 @@ -/** -* @file timer.hpp -* -* @brief A generic way for measuring time -*/ - -#ifndef TIMER_HPP -#define TIMER_HPP +#pragma once #include "core/properties.hpp" @@ -99,5 +92,3 @@ namespace syrec { }; } // namespace syrec - -#endif diff --git a/mqt/syrec/bindings.cpp b/mqt/syrec/bindings.cpp index 5f14658a..5c022073 100644 --- a/mqt/syrec/bindings.cpp +++ b/mqt/syrec/bindings.cpp @@ -1,5 +1,6 @@ #include "algorithms/simulation/simple_simulation.hpp" -#include "algorithms/synthesis/syrec_synthesis.hpp" +#include "algorithms/synthesis/syrec_synthesis_additional_lines.hpp" +#include "algorithms/synthesis/syrec_synthesis_no_additional_lines.hpp" #include "core/circuit.hpp" #include "core/gate.hpp" #include "core/properties.hpp" @@ -84,7 +85,8 @@ PYBIND11_MODULE(pysyrec, m) { .def_readwrite("targets", &gate::targets) .def_readwrite("type", &gate::type); - m.def("synthesis", &syrec_synthesis, "circ"_a, "program"_a, "settings"_a = properties::ptr(), "statistics"_a = properties::ptr()); + m.def("syrec_synthesis_additional_lines", &SyrecSynthesisAdditionalLines::synthesize, "circ"_a, "program"_a, "settings"_a = properties::ptr(), "statistics"_a = properties::ptr()); + m.def("syrec_synthesis_no_additional_lines", &SyrecSynthesisNoAdditionalLines::synthesize, "circ"_a, "program"_a, "settings"_a = properties::ptr(), "statistics"_a = properties::ptr()); m.def("simple_simulation", &simple_simulation, "output"_a, "circ"_a, "input"_a, "statistics"_a = properties::ptr()); #ifdef VERSION_INFO diff --git a/mqt/syrec/syrec_editor.py b/mqt/syrec/syrec_editor.py index c0fe3165..175f9ab2 100644 --- a/mqt/syrec/syrec_editor.py +++ b/mqt/syrec/syrec_editor.py @@ -133,6 +133,10 @@ class SyReCEditor(QWidget): before_build = None parser_failed = None + synthesize_with_additional_lines = 0 + synthesize_without_additional_lines = 0 + + def __init__(self, parent=None): super().__init__() @@ -161,11 +165,59 @@ def setup_actions(self): self.sim_action = QAction(QIcon.fromTheme('x-office-spreadsheet'), '&Sim...', self.parent) # system-run self.stat_action = QAction(QIcon.fromTheme('applications-other'), '&Stats...', self.parent) + self.buttonAddLines = QRadioButton("SyReC with Add. Lines", self) + self.buttonAddLines.toggled.connect(self.item_selected) + + + self.buttonNoLines = QRadioButton("SyReC with no lines", self) + self.buttonNoLines.setChecked(True) + self.synthesize_without_additional_lines = 1 + self.buttonNoLines.toggled.connect(self.item_selected) + + self.sim_action.setDisabled(True) + self.stat_action.setDisabled(True) + self.open_action.triggered.connect(self.open) + self.build_action.triggered.connect(self.build) + self.sim_action.triggered.connect(self.sim) + self.stat_action.triggered.connect(self.stat) + def item_selected(self): + + # Disable sim and stat function + self.sim_action.setDisabled(True) + self.stat_action.setDisabled(True) + + # if first button is selected + if self.sender() == self.buttonAddLines: + if(self.buttonAddLines.isChecked()): + self.synthesize_with_additional_lines = 1 + self.synthesize_without_additional_lines = 0 + # making other check box to uncheck + self.buttonNoLines.setChecked(False) + else: + self.synthesize_with_additional_lines = 0 + self.synthesize_without_additional_lines = 1 + # making other check box to uncheck + self.buttonNoLines.setChecked(True) + + + # if second button is selected + elif self.sender() == self.buttonNoLines: + if(self.buttonNoLines.isChecked()): + self.synthesize_with_additional_lines = 0 + self.synthesize_without_additional_lines = 1 + # making other check box to uncheck + self.buttonAddLines.setChecked(False) + else: + self.synthesize_with_additional_lines = 1 + self.synthesize_without_additional_lines = 0 + # making other check box to uncheck + self.buttonAddLines.setChecked(True) + def writeEditorContentsToFile(self): data = QFile("/tmp/out.src") if data.open(QFile.OpenModeFlag.WriteOnly | QFile.OpenModeFlag.Truncate): @@ -175,6 +227,7 @@ def writeEditorContentsToFile(self): return data.close() + return def open(self): @@ -193,14 +246,15 @@ def load(self, filename): return def build(self): + if self.before_build is not None: self.before_build() self.writeEditorContentsToFile() - prog = program() + self.prog = program() - error_string = prog.read("/tmp/out.src") + error_string = self.prog.read("/tmp/out.src") if error_string == "PARSE_STRING_FAILED": if self.parser_failed is not None: @@ -212,52 +266,38 @@ def build(self): self.build_failed(error_string) return - circ = circuit() + self.circ = circuit() - synthesis(circ, prog) + if (self.synthesize_with_additional_lines): + syrec_synthesis_additional_lines(self.circ, self.prog) + else: + syrec_synthesis_no_additional_lines(self.circ, self.prog) + + self.sim_action.setDisabled(False) + self.stat_action.setDisabled(False) - num_consts = sum(c is not None for c in circ.constants) - num_garbage = sum(circ.garbage) - print("Number Of Gates : ", circ.num_gates) - print("Number Of Lines : ", circ.lines) - print("Number Of Inputs : ", circ.lines - num_consts) + num_consts = sum(c is not None for c in self.circ.constants) + num_garbage = sum(self.circ.garbage) + print("Number Of Gates : ", self.circ.num_gates) + print("Number Of Lines : ", self.circ.lines) + print("Number Of Inputs : ", self.circ.lines - num_consts) print("Number Of Constants : ", num_consts) - print("Number of Outputs : ", circ.lines - num_garbage) + print("Number of Outputs : ", self.circ.lines - num_garbage) print("Number of Garbage Lines : ", num_garbage) if self.build_successful is not None: - self.build_successful(circ) + self.build_successful(self.circ) return def stat(self): - if self.before_build is not None: - self.before_build() - - self.writeEditorContentsToFile() - - prog = program() - - error_string = prog.read("/tmp/out.src") - if error_string == "PARSE_STRING_FAILED": - if self.parser_failed is not None: - self.parser_failed("Editor is Empty") - return - - elif error_string != "": - if self.build_failed is not None: - self.build_failed(error_string) - return - circ = circuit() - synthesis(circ, prog) + gates = self.circ.num_gates + lines = self.circ.lines - gates = circ.num_gates - lines = circ.lines + qc = self.circ.quantum_cost() - qc = circ.quantum_cost() - - tc = circ.transistor_cost() + tc = self.circ.transistor_cost() temp = "Gates:\t\t{}\nLines:\t\t{}\nQuantum Costs:\t{}\nTransistor Costs:\t{}\n" @@ -272,45 +312,26 @@ def stat(self): return - def sim(self): - if self.before_build is not None: - self.before_build() - - self.writeEditorContentsToFile() - - prog = program() - error_string = prog.read("/tmp/out.src") - if error_string == "PARSE_STRING_FAILED": - if self.parser_failed is not None: - self.parser_failed("Editor is Empty") - return - elif error_string != "": - if self.build_failed is not None: - self.build_failed(error_string) - return - - circ = circuit() - - synthesis(circ, prog) + def sim(self): bit_mask = 0 bit_pos = 0 bit1_mask = 0 - for i in circ.constants: + for i in self.circ.constants: if i is None: bit_mask = bit_mask + 2 ** bit_pos bit_pos += 1 - no_of_bits = len(circ.constants) + no_of_bits = len(self.circ.constants) input_list = [x & bit_mask for x in range(2 ** no_of_bits)] - for i in range(len(circ.constants)): - if circ.constants[i]: + for i in range(len(self.circ.constants)): + if self.circ.constants[i]: bit1_mask = bit1_mask + 2 ** i input_list = [i + bit1_mask for i in input_list] @@ -328,22 +349,20 @@ def sim(self): settings = properties() for i in input_list: - my_inp_bitset = bitset(circ.lines, i) - my_out_bitset = bitset(circ.lines) + my_inp_bitset = bitset(self.circ.lines, i) + my_out_bitset = bitset(self.circ.lines) - simple_simulation(my_out_bitset, circ, my_inp_bitset, settings) + simple_simulation(my_out_bitset, self.circ, my_inp_bitset, settings) combination_inp.append(str(my_inp_bitset)) combination_out.append(str(my_out_bitset)) - # sorted_inp_str=sorted(combination_inp,key=lambda x: int(x,2)) - sorted_ind = sorted(range(len(combination_inp)), key=lambda k: int(combination_inp[k], 2)) for i in sorted_ind: final_inp.append(combination_inp[i]) final_out.append(combination_out[i]) - num_inputs = len(circ.inputs) + num_inputs = len(self.circ.inputs) # Initiate table @@ -369,11 +388,11 @@ def sim(self): # Fill Table for i in range(num_inputs): - input_signal = QTableWidgetItem(circ.inputs[i]) + input_signal = QTableWidgetItem(self.circ.inputs[i]) input_signal.setTextAlignment(Qt.AlignmentFlag.AlignCenter) self.table.setItem(1, i, QTableWidgetItem(input_signal)) - output_signal = QTableWidgetItem(circ.outputs[i]) + output_signal = QTableWidgetItem(self.circ.outputs[i]) output_signal.setTextAlignment(Qt.AlignmentFlag.AlignCenter) self.table.setItem(1, i + num_inputs, QTableWidgetItem(output_signal)) @@ -389,13 +408,8 @@ def sim(self): self.table.horizontalHeader().setStretchLastSection(True) self.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Stretch) - - # Add Table to QWidget - - # show table self.show() - class SyReCHighligher(QSyntaxHighlighter): def __init__(self, parent): QSyntaxHighlighter.__init__(self, parent) @@ -428,7 +442,6 @@ def highlightBlock(self, text): self.setFormat(index, length, rule[1]) match = expression.match(text, offset=index + length) - class QtSyReCEditor(SyReCEditor): def __init__(self, parent=None): SyReCEditor.__init__(self, parent) @@ -442,8 +455,6 @@ def setText(self, text): def getText(self): return self.widget.toPlainText() - - class LineNumberArea(QWidget): def __init__(self, editor): QWidget.__init__(self, editor) @@ -455,7 +466,6 @@ def sizeHint(self): def paintEvent(self, event): self.codeEditor.lineNumberAreaPaintEvent(event) - class CodeEditor(QPlainTextEdit): def __init__(self, parent=None): QPlainTextEdit.__init__(self, parent) @@ -549,11 +559,6 @@ def addMessage(self, message): item = QTreeWidgetItem([message]) self.addTopLevelItem(item) - # def addLineAndMessage( self, line, message ): - # item = QTreeWidgetItem( [ str( int(line) + 1 ), message ] ) - # self.addTopLevelItem( item ) - - class MainWindow(QMainWindow): def __init__(self, parent=None): QWidget.__init__(self, parent) @@ -595,7 +600,8 @@ def setup_toolbar(self): toolbar.addAction(self.editor.build_action) toolbar.addAction(self.editor.sim_action) toolbar.addAction(self.editor.stat_action) - + toolbar.addWidget(self.editor.buttonAddLines) + toolbar.addWidget(self.editor.buttonNoLines) def main(): a = QApplication([]) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3022f3ec..a2784a7b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,7 @@ add_library(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/algorithms/synthesis/syrec_synthesis.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/algorithms/synthesis/syrec_synthesis_additional_lines.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/algorithms/synthesis/syrec_synthesis_no_additional_lines.cpp ${CMAKE_CURRENT_SOURCE_DIR}/algorithms/simulation/simple_simulation.cpp ${CMAKE_CURRENT_SOURCE_DIR}/algorithms/synthesis/dd_synthesis.cpp ${CMAKE_CURRENT_SOURCE_DIR}/algorithms/synthesis/encoding.cpp @@ -7,6 +9,8 @@ add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/simulation/simple_simulation.hpp ${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/synthesis/syrec_synthesis.hpp + ${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/synthesis/syrec_synthesis_additional_lines.hpp + ${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/synthesis/syrec_synthesis_no_additional_lines.hpp ${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/synthesis/dd_synthesis.hpp ${${PROJECT_NAME}_SOURCE_DIR}/include/algorithms/synthesis/encoding.hpp diff --git a/src/algorithms/synthesis/syrec_synthesis.cpp b/src/algorithms/synthesis/syrec_synthesis.cpp index c17aebff..74cde69c 100644 --- a/src/algorithms/synthesis/syrec_synthesis.cpp +++ b/src/algorithms/synthesis/syrec_synthesis.cpp @@ -19,7 +19,7 @@ namespace syrec { _stmts(stmts) {} // Operator needs this signature to work - void operator()(gate& g) const { + void operator()(gate const& g) const { if (!_stmts.empty()) { _circ.annotate(g, "lno", std::to_string(_stmts.top()->line_number)); } @@ -31,10 +31,10 @@ namespace syrec { }; // Helper Functions for the synthesis methods - standard_syrec_synthesizer::standard_syrec_synthesizer(circuit& circ, const program& prog [[maybe_unused]]): + SyrecSynthesis::SyrecSynthesis(circuit& circ): _circ(circ) { - free_const_lines_map.insert(std::make_pair(false, std::vector())); - free_const_lines_map.insert(std::make_pair(true, std::vector())); + free_const_lines_map.try_emplace(false /* emplacing a default constructed object */); + free_const_lines_map.try_emplace(true /* emplacing a default constructed object */); // root anlegen cct_man.current = add_vertex(cct_man.tree); @@ -46,270 +46,50 @@ namespace syrec { add_edge(cct_man.root, cct_man.current, cct_man.tree); } - void standard_syrec_synthesizer::set_main_module(const module::ptr& main_module) { + void SyrecSynthesis::set_main_module(const module::ptr& main_module) { assert(modules.empty()); modules.push(main_module); } - bool standard_syrec_synthesizer::on_module(const module::ptr& main) { + bool SyrecSynthesis::on_module(const module::ptr& main) { for (const auto& stat: main->statements) { - if (!full_statement(stat)) { - if (!on_statement(stat)) { - return false; - } + if (process_statement(stat)) { + return false; } } return assemble_circuit(cct_man.root); } - /// checking the entire statement - bool standard_syrec_synthesizer::full_statement(const statement::ptr& statement) { - bool okay = false; - if (auto* stat = dynamic_cast(statement.get())) { - okay = full_statement(*stat); - } else { - return false; - } - - return okay; - } - - bool standard_syrec_synthesizer::full_statement(const assign_statement& statement) { - std::vector d, dd, stat_lhs, comp, ddd; - std::vector lines; - get_variables(statement.lhs, stat_lhs); - - op_rhs_lhs_expression(statement.rhs, d); - - if (op_vec.empty()) { - return false; - } - flow(statement.rhs, ddd); - - /// Only when the rhs input signals are repeated (since the results are stored in the rhs) - - if (check_repeats()) { - flow(statement.rhs, dd); - - if (exp_op_vector.size() == 1) { - if (exp_op_vector.at(0) == 1 or exp_op_vector.at(0) == 2) { - /// cancel out the signals - - exp_op_vector.clear(); - assign_op_vector.clear(); - exp_lhs_vector.clear(); - exp_rhs_vector.clear(); - op_vec.clear(); - } else { - if (statement.op == 1) { - expression_single_op(1, exp_lhs_vector.at(0), stat_lhs); - expression_single_op(1, exp_rhs_vector.at(0), stat_lhs); - exp_op_vector.clear(); - assign_op_vector.clear(); - exp_lhs_vector.clear(); - exp_rhs_vector.clear(); - op_vec.clear(); - } else { - expression_single_op(statement.op, exp_lhs_vector.at(0), stat_lhs); - expression_single_op(exp_op_vector.at(0), exp_rhs_vector.at(0), stat_lhs); - exp_op_vector.clear(); - assign_op_vector.clear(); - exp_lhs_vector.clear(); - exp_rhs_vector.clear(); - op_vec.clear(); - } - } - - } else { - if (exp_lhs_vector.at(0) == exp_rhs_vector.at(0)) { - if (exp_op_vector.at(0) == 1 or exp_op_vector.at(0) == 2) { - /// cancel out the signals - } else if (exp_op_vector.at(0) != 1 or exp_op_vector.at(0) != 2) { - expression_single_op(statement.op, exp_lhs_vector.at(0), stat_lhs); - expression_single_op(exp_op_vector.at(0), exp_rhs_vector.at(0), stat_lhs); - } - } else { - solver(stat_lhs, statement.op, exp_lhs_vector.at(0), exp_op_vector.at(0), exp_rhs_vector.at(0)); - } - - unsigned j = 0; - unsigned z; - std::vector stat_assign_op; - if ((exp_op_vector.size() % 2) == 0) { - z = ((exp_op_vector.size()) / (2)); - } else { - z = (((exp_op_vector.size()) - 1) / (2)); - } - - for (unsigned k = 0; k <= z - 1; k++) { - stat_assign_op.push_back(assign_op_vector.at(k)); - } - - /// Assignment operations - - std::reverse(stat_assign_op.begin(), stat_assign_op.end()); - - /// If reversible assignment is "-", the assignment operations must negated appropriately - - if (statement.op == 1) { - for (unsigned int& i: stat_assign_op) { - if (i == 0) { - i = 1; - } else if (i == 1) { - i = 0; - } else { - continue; - } - } - } - - for (unsigned i = 1; i <= exp_op_vector.size() - 1; i++) { - /// when both rhs and lhs exist - if ((exp_lhs_vector.at(i) != comp) && (exp_rhs_vector.at(i) != comp)) { - if (exp_lhs_vector.at(i) == exp_rhs_vector.at(i)) { - if (exp_op_vector.at(i) == 1 or exp_op_vector.at(i) == 2) { - /// cancel out the signals - j = j + 1; - } else if (exp_op_vector.at(i) != 1 or exp_op_vector.at(i) != 2) { - if (stat_assign_op.at(j) == 1) { - expression_single_op(1, exp_lhs_vector.at(i), stat_lhs); - expression_single_op(1, exp_rhs_vector.at(i), stat_lhs); - j = j + 1; - } else { - expression_single_op(stat_assign_op.at(j), exp_lhs_vector.at(i), stat_lhs); - expression_single_op(exp_op_vector.at(i), exp_rhs_vector.at(i), stat_lhs); - j = j + 1; - } - } - } else { - solver(stat_lhs, stat_assign_op.at(j), exp_lhs_vector.at(i), exp_op_vector.at(i), exp_rhs_vector.at(i)); - j = j + 1; - } - } - - /// when only rhs exists - else if ((exp_lhs_vector.at(i) == comp) && (exp_rhs_vector.at(i) != comp)) { - exp_evaluate(lines, stat_assign_op.at(j), exp_rhs_vector.at(i), stat_lhs); - - j = j + 1; - } - - /// when only lhs exists - else if ((exp_lhs_vector.at(i) != comp) && (exp_rhs_vector.at(i) == comp)) { - exp_evaluate(lines, stat_assign_op.at(j), exp_rhs_vector.at(i), stat_lhs); - - j = j + 1; - } else if ((exp_lhs_vector.at(i) == comp) && (exp_rhs_vector.at(i) == comp)) { - } - } - exp_op_vector.clear(); - assign_op_vector.clear(); - exp_lhs_vector.clear(); - exp_rhs_vector.clear(); - op_vec.clear(); - } - } else { - exp_op_vector.clear(); - assign_op_vector.clear(); - exp_lhs_vector.clear(); - exp_rhs_vector.clear(); - op_vec.clear(); - return false; - } - - exp_op_vector.clear(); - assign_op_vector.clear(); - exp_lhs_vector.clear(); - exp_rhs_vector.clear(); - op_vec.clear(); - return true; - } - - bool standard_syrec_synthesizer::flow(const expression::ptr& expression, std::vector& v) { - if (auto* binary = dynamic_cast(expression.get())) { - return flow(*binary, v); - } else if (auto* var = dynamic_cast(expression.get())) { - return flow(*var, v); - } else { - return false; - } - } - - bool standard_syrec_synthesizer::flow(const variable_expression& expression, std::vector& v) { - get_variables(expression.var, v); - return true; - } - - /// generating LHS and RHS (can be whole expressions as well) - bool standard_syrec_synthesizer::flow(const binary_expression& expression, std::vector& v [[maybe_unused]]) { - std::vector lhs, rhs, comp; - assign_op_vector.push_back(expression.op); - - if (!flow(expression.lhs, lhs) || !flow(expression.rhs, rhs)) { - return false; - } - - exp_lhs_vector.push_back(lhs); - exp_rhs_vector.push_back(rhs); - exp_op_vector.push_back(expression.op); - return true; - } - - bool standard_syrec_synthesizer::solver(const std::vector& stat_lhs, unsigned stat_op, const std::vector& exp_lhs, unsigned exp_op, const std::vector& exp_rhs) { - std::vector lines; - if (stat_op == exp_op) { - if (exp_op == 1) { - expression_single_op(1, exp_lhs, stat_lhs); - expression_single_op(0, exp_rhs, stat_lhs); - } else { - expression_single_op(stat_op, exp_lhs, stat_lhs); - expression_single_op(stat_op, exp_rhs, stat_lhs); - } - } else { - sub_flag = true; - exp_evaluate(lines, exp_op, exp_lhs, exp_rhs); - sub_flag = false; - exp_evaluate(lines, stat_op, lines, stat_lhs); - sub_flag = true; - if (exp_op < 3) { - expression_op_inverse(exp_op, exp_lhs, exp_rhs); - } - } - sub_flag = false; - return true; - } /// If the input signals are repeated (i.e., rhs input signals are repeated) - bool standard_syrec_synthesizer::check_repeats() { + bool SyrecSynthesis::check_repeats() { std::vector check_lhs_vec(exp_lhs_vector.cbegin(), exp_lhs_vector.cend()); std::vector check_rhs_vec(exp_rhs_vector.cbegin(), exp_rhs_vector.cend()); for (unsigned k = 0; k < check_lhs_vec.size(); k++) { if (check_lhs_vec.at(k).empty()) { - check_lhs_vec.erase(check_lhs_vec.begin() + (k)); + check_lhs_vec.erase(check_lhs_vec.begin() + k); } } for (unsigned k = 0; k < check_rhs_vec.size(); k++) { if (check_rhs_vec.at(k).empty()) { - check_rhs_vec.erase(check_rhs_vec.begin() + (k)); + check_rhs_vec.erase(check_rhs_vec.begin() + k); } } for (int i = 0; i < int(check_rhs_vec.size()); i++) { for (int j = 0; j < int(check_rhs_vec.size()); j++) { - if (j != i) { - if (check_rhs_vec.at(i) == check_rhs_vec.at(j)) { - exp_op_vector.clear(); - exp_lhs_vector.clear(); - exp_rhs_vector.clear(); - return true; - } + if ((j != i) && (check_rhs_vec.at(i) == check_rhs_vec.at(j))) { + exp_op_vector.clear(); + exp_lhs_vector.clear(); + exp_rhs_vector.clear(); + return true; } } } - for (auto& i: check_lhs_vec) { - for (auto& j: check_rhs_vec) { + for (auto const& i: check_lhs_vec) { + for (auto const& j: check_rhs_vec) { if (i == j) { exp_op_vector.clear(); exp_lhs_vector.clear(); @@ -325,54 +105,35 @@ namespace syrec { return false; } - /// generating LHS and RHS (not whole expressions, just the corresponding variables) - bool standard_syrec_synthesizer::op_rhs_lhs_expression(const expression::ptr& expression, std::vector& v) { - if (auto* binary = dynamic_cast(expression.get())) { - return op_rhs_lhs_expression(*binary, v); - } else if (auto* var = dynamic_cast(expression.get())) { - return op_rhs_lhs_expression(*var, v); - } else { - return false; - } + bool SyrecSynthesis::op_rhs_lhs_expression([[maybe_unused]] const expression::ptr& expression, [[maybe_unused]] std::vector& v) { + return true; } - - bool standard_syrec_synthesizer::op_rhs_lhs_expression(const variable_expression& expression, std::vector& v) { - get_variables(expression.var, v); + bool SyrecSynthesis::op_rhs_lhs_expression([[maybe_unused]] const variable_expression& expression, [[maybe_unused]] std::vector& v) { return true; } - - bool standard_syrec_synthesizer::op_rhs_lhs_expression(const binary_expression& expression, std::vector& v) { - std::vector lhs, rhs; - - if (!op_rhs_lhs_expression(expression.lhs, lhs) || !op_rhs_lhs_expression(expression.rhs, rhs)) { - return false; - } - - v = rhs; - op_vec.push_back(expression.op); + bool SyrecSynthesis::op_rhs_lhs_expression([[maybe_unused]] const binary_expression& expression, [[maybe_unused]] std::vector& v) { return true; } - /////////When the input signals are not repeated////////////////// - bool standard_syrec_synthesizer::on_statement(const statement::ptr& statement) { + bool SyrecSynthesis::on_statement(const statement::ptr& statement) { _stmts.push(statement); bool okay = false; - if (auto* swap_stat = dynamic_cast(statement.get())) { - okay = on_statement(*swap_stat); - } else if (auto* unary_stat = dynamic_cast(statement.get())) { - okay = on_statement(*unary_stat); - } else if (auto* assign_stat = dynamic_cast(statement.get())) { - okay = on_statement(*assign_stat); - } else if (auto* if_stat = dynamic_cast(statement.get())) { - okay = on_statement(*if_stat); - } else if (auto* for_stat = dynamic_cast(statement.get())) { - okay = on_statement(*for_stat); - } else if (auto* call_stat = dynamic_cast(statement.get())) { - okay = on_statement(*call_stat); - } else if (auto* uncall_stat = dynamic_cast(statement.get())) { - okay = on_statement(*uncall_stat); - } else if (auto* skip_stat = dynamic_cast(statement.get())) { - okay = on_statement(*skip_stat); + if (auto const* swapStat = dynamic_cast(statement.get())) { + okay = on_statement(*swapStat); + } else if (auto const* unaryStat = dynamic_cast(statement.get())) { + okay = on_statement(*unaryStat); + } else if (auto const* assignStat = dynamic_cast(statement.get())) { + okay = on_statement(*assignStat); + } else if (auto const* ifStat = dynamic_cast(statement.get())) { + okay = on_statement(*ifStat); + } else if (auto const* forStat = dynamic_cast(statement.get())) { + okay = on_statement(*forStat); + } else if (auto const* callStat = dynamic_cast(statement.get())) { + okay = on_statement(*callStat); + } else if (auto const* uncallStat = dynamic_cast(statement.get())) { + okay = on_statement(*uncallStat); + } else if (auto const* skipStat = statement.get()) { + okay = on_statement(*skipStat); } else { return false; } @@ -381,8 +142,9 @@ namespace syrec { return okay; } - bool standard_syrec_synthesizer::on_statement(const swap_statement& statement) { - std::vector lhs, rhs; + bool SyrecSynthesis::on_statement(const swap_statement& statement) { + std::vector lhs; + std::vector rhs; get_variables(statement.lhs, lhs); get_variables(statement.rhs, rhs); @@ -394,7 +156,7 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::on_statement(const unary_statement& statement) { + bool SyrecSynthesis::on_statement(const unary_statement& statement) { // load variable std::vector var; get_variables(statement.var, var); @@ -415,74 +177,30 @@ namespace syrec { return true; } - /// Function when the assignment statements does not include repeated input signals - bool standard_syrec_synthesizer::on_statement(const assign_statement& statement) { - std::vector lhs, rhs, d; + bool SyrecSynthesis::on_statement(const assign_statement& statement) { + std::vector lhs; + std::vector rhs; + std::vector d; get_variables(statement.lhs, lhs); op_rhs_lhs_expression(statement.rhs, d); - on_expression(statement.rhs, rhs, lhs, statement.op); + SyrecSynthesis::on_expression(statement.rhs, rhs, lhs, statement.op); op_vec.clear(); bool status = false; switch (statement.op) { case assign_statement::add: { - if (!exp_opp.empty() && exp_opp.top() == statement.op) { - status = increase_new(lhs, exp_lhss.top()); - status = increase_new(lhs, exp_rhss.top()); - exp_opp.pop(); - exp_lhss.pop(); - exp_rhss.pop(); - } else { - status = increase_new(lhs, rhs); - } - while (!exp_opp.empty()) { - expression_op_inverse(exp_opp.top(), exp_lhss.top(), exp_rhss.top()); - sub_flag = false; - exp_opp.pop(); - exp_lhss.pop(); - exp_rhss.pop(); - } + assign_add(status, lhs, rhs, statement.op); } break; case assign_statement::subtract: { - if (!exp_opp.empty() && exp_opp.top() == statement.op) { - status = decrease_new(lhs, exp_lhss.top()); - status = increase_new(lhs, exp_rhss.top()); - exp_opp.pop(); - exp_lhss.pop(); - exp_rhss.pop(); - } else { - status = decrease_new(lhs, rhs); - } - while (!exp_opp.empty()) { - expression_op_inverse(exp_opp.top(), exp_lhss.top(), exp_rhss.top()); - sub_flag = false; - exp_opp.pop(); - exp_lhss.pop(); - exp_rhss.pop(); - } + assign_subtract(status, lhs, rhs, statement.op); } break; case assign_statement::exor: { - if (!exp_opp.empty() && exp_opp.top() == statement.op) { - status = bitwise_cnot(lhs, exp_lhss.top()); - status = bitwise_cnot(lhs, exp_rhss.top()); - exp_opp.pop(); - exp_lhss.pop(); - exp_rhss.pop(); - } else { - status = bitwise_cnot(lhs, rhs); - } - while (!exp_opp.empty()) { - expression_op_inverse(exp_opp.top(), exp_lhss.top(), exp_rhss.top()); - sub_flag = false; - exp_opp.pop(); - exp_lhss.pop(); - exp_rhss.pop(); - } + assign_exor(status, lhs, rhs, statement.op); } break; default: @@ -492,11 +210,10 @@ namespace syrec { return status; } - bool standard_syrec_synthesizer::on_statement(const if_statement& statement) { + bool SyrecSynthesis::on_statement(const if_statement& statement) { // calculate expression - std::vector expression_result, lhs_stat; - unsigned op = 0u; - on_expression(statement.condition, expression_result, lhs_stat, op); + std::vector expression_result; + on_expression(statement.condition, expression_result, {}, 0U); assert(expression_result.size() == 1u); // add new helper line @@ -505,11 +222,9 @@ namespace syrec { // activate this line add_active_control(helper_line); - for (const auto& stat: statement.then_statements) { - if (!full_statement(stat)) { - if (!on_statement(stat)) { - return false; - } + for (const statement::ptr& stat: statement.then_statements) { + if (process_statement(stat)) { + return false; } } @@ -518,11 +233,9 @@ namespace syrec { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(helper_line); add_active_control(helper_line); - for (const auto& stat: statement.else_statements) { - if (!full_statement(stat)) { - if (!on_statement(stat)) { - return false; - } + for (const statement::ptr& stat: statement.else_statements) { + if (process_statement(stat)) { + return false; } } @@ -533,8 +246,8 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::on_statement(const for_statement& statement) { - const auto [nfrom, nto] = statement.range; + bool SyrecSynthesis::on_statement(const for_statement& statement) { + const auto& [nfrom, nto] = statement.range; const unsigned from = nfrom ? nfrom->evaluate(loop_map) : 1u; // default value is 1u const unsigned to = nto->evaluate(loop_map); @@ -550,17 +263,15 @@ namespace syrec { } for (const auto& stat: statement.statements) { - if (!full_statement(stat)) { - if (!on_statement(stat)) { - return false; - } + if (process_statement(stat)) { + return false; } } } } else if (from > to) { - for (int i = (int)from; i >= (int)to; i -= (int)step) { + for (auto i = static_cast(from); i >= static_cast(to); i -= static_cast(step)) { // adjust loop variable if necessary if (!loop_variable.empty()) { @@ -568,10 +279,8 @@ namespace syrec { } for (const auto& stat: statement.statements) { - if (!full_statement(stat)) { - if (!on_statement(stat)) { - return false; - } + if (process_statement(stat)) { + return false; } } } @@ -584,11 +293,11 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::on_statement(const call_statement& statement) { + bool SyrecSynthesis::on_statement(const call_statement& statement) { // 1. Adjust the references module's parameters to the call arguments for (unsigned i = 0u; i < statement.parameters.size(); ++i) { - const std::string& parameter = statement.parameters.at(i); - const auto& module_parameter = statement.target->parameters.at(i); + const std::string& parameter = statement.parameters.at(i); + const variable::ptr& module_parameter = statement.target->parameters.at(i); module_parameter->set_reference(modules.top()->find_parameter_or_variable(parameter)); } @@ -597,20 +306,17 @@ namespace syrec { add_variables(_circ, statement.target->variables); modules.push(statement.target); - for (const auto& stat: statement.target->statements) { - if (!full_statement(stat)) { - if (!on_statement(stat)) { - return false; - } + for (const statement::ptr& stat: statement.target->statements) { + if (process_statement(stat)) { + return false; } } - modules.pop(); return true; } - bool standard_syrec_synthesizer::on_statement(const uncall_statement& statement) { + bool SyrecSynthesis::on_statement(const uncall_statement& statement) { // 1. Adjust the references module's parameters to the call arguments for (unsigned i = 0u; i < statement.parameters.size(); ++i) { const std::string& parameter = statement.parameters.at(i); @@ -627,10 +333,8 @@ namespace syrec { const auto statements = statement.target->statements; for (auto it = statements.rbegin(); it != statements.rend(); ++it) { const auto reverse_statement = (*it)->reverse(); - if (!full_statement(reverse_statement)) { - if (!on_statement(reverse_statement)) { - return false; - } + if (process_statement(reverse_statement)) { + return false; } } @@ -639,38 +343,61 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::on_statement(const skip_statement& statement [[maybe_unused]]) { + bool SyrecSynthesis::on_statement(const skip_statement& statement [[maybe_unused]]) { return true; } - bool standard_syrec_synthesizer::on_expression(const expression::ptr& expression, std::vector& lines, std::vector& lhs_stat, unsigned op) { - if (auto* numeric = dynamic_cast(expression.get())) { + bool SyrecSynthesis::on_expression(const expression::ptr& expression, std::vector& lines, std::vector const& lhs_stat, unsigned op) { + if (auto const* numeric = dynamic_cast(expression.get())) { return on_expression(*numeric, lines); - } else if (auto* variable = dynamic_cast(expression.get())) { + } else if (auto const* variable = dynamic_cast(expression.get())) { return on_expression(*variable, lines); - } else if (auto* binary = dynamic_cast(expression.get())) { + } else if (auto const* binary = dynamic_cast(expression.get())) { return on_expression(*binary, lines, lhs_stat, op); - } else if (auto* shift = dynamic_cast(expression.get())) { + } else if (auto const* shift = dynamic_cast(expression.get())) { return on_expression(*shift, lines, lhs_stat, op); } else { return false; } } - bool standard_syrec_synthesizer::on_expression(const numeric_expression& expression, std::vector& lines) { + bool SyrecSynthesis::on_expression(const shift_expression& expression, std::vector& lines, std::vector const& lhs_stat, unsigned op) { + std::vector lhs; + if (!on_expression(expression.lhs, lhs, lhs_stat, op)) { + return false; + } + + unsigned rhs = expression.rhs->evaluate(loop_map); + + switch (expression.op) { + case shift_expression::left: // << + get_constant_lines(expression.bitwidth(), 0u, lines); + left_shift(lines, lhs, rhs); + break; + case shift_expression::right: // << + get_constant_lines(expression.bitwidth(), 0u, lines); + right_shift(lines, lhs, rhs); + break; + default: + return false; + } + + return true; + } + + bool SyrecSynthesis::on_expression(const numeric_expression& expression, std::vector& lines) { get_constant_lines(expression.bitwidth(), expression.value->evaluate(loop_map), lines); return true; } - bool standard_syrec_synthesizer::on_expression(const variable_expression& expression, std::vector& lines) { + bool SyrecSynthesis::on_expression(const variable_expression& expression, std::vector& lines) { get_variables(expression.var, lines); return true; } - /// Function when the assignment statements consist of binary expressions and does not include repeated input signals - - bool standard_syrec_synthesizer::on_expression(const binary_expression& expression, std::vector& lines, std::vector& lhs_stat, unsigned op) { - std::vector lhs, rhs; + bool SyrecSynthesis::on_expression(const binary_expression& expression, std::vector& lines, std::vector const& lhs_stat, unsigned op) { + std::vector lhs; + std::vector rhs; if (!on_expression(expression.lhs, lhs, lhs_stat, op) || !on_expression(expression.rhs, rhs, lhs_stat, op)) { return false; @@ -680,24 +407,19 @@ namespace syrec { exp_rhss.push(rhs); exp_opp.push(expression.op); - if (exp_opp.size() == op_vec.size()) { - if (exp_opp.top() == op) { - return true; - } + if ((exp_opp.size() == op_vec.size()) && (exp_opp.top() == op)) { + return true; } switch (expression.op) { case binary_expression::add: // + - increase_new(rhs, lhs); - lines = rhs; + exp_add(expression.bitwidth(), lines, lhs, rhs); break; case binary_expression::subtract: // - - decrease_new_assign(rhs, lhs); - lines = rhs; + exp_subtract(expression.bitwidth(), lines, lhs, rhs); break; case binary_expression::exor: // ^ - bitwise_cnot(rhs, lhs); // duplicate lhs - lines = rhs; + exp_exor(expression.bitwidth(), lines, lhs, rhs); break; case binary_expression::multiply: // * get_constant_lines(expression.bitwidth(), 0u, lines); @@ -707,7 +429,7 @@ namespace syrec { get_constant_lines(expression.bitwidth(), 0u, lines); division(lines, lhs, rhs); break; - case binary_expression::modulo: { + case binary_expression::modulo: { // % get_constant_lines(expression.bitwidth(), 0u, lines); std::vector quot; get_constant_lines(expression.bitwidth(), 0u, quot); @@ -762,69 +484,20 @@ namespace syrec { return true; } - /// This function is used when input signals (rhs) are equal (just to solve statements individually) - bool standard_syrec_synthesizer::exp_evaluate(std::vector& lines, unsigned op, const std::vector& lhs, const std::vector& rhs) { - switch (op) { - case binary_expression::add: // + - increase_new(rhs, lhs); - lines = rhs; - break; - case binary_expression::subtract: // - - if (sub_flag) { - decrease_new_assign(rhs, lhs); - lines = rhs; - } else { - decrease_new(rhs, lhs); - lines = rhs; - } - break; - case binary_expression::exor: // ^ - bitwise_cnot(rhs, lhs); // duplicate lhs - lines = rhs; - break; - default: - return false; - } - - return true; - } - - bool standard_syrec_synthesizer::on_expression(const shift_expression& expression, std::vector& lines, std::vector& lhs_stat, unsigned op) { - std::vector lhs; - if (!on_expression(expression.lhs, lhs, lhs_stat, op)) { - return false; - } - - unsigned rhs = expression.rhs->evaluate(loop_map); - - switch (expression.op) { - case shift_expression::left: // << - get_constant_lines(expression.bitwidth(), 0u, lines); - left_shift(lines, lhs, rhs); - break; - case shift_expression::right: // << - get_constant_lines(expression.bitwidth(), 0u, lines); - right_shift(lines, lhs, rhs); - break; - default: - return false; - } - - return true; - } + /// Function when the assignment statements consist of binary expressions and does not include repeated input signals //********************************************************************** //***** Unary Operations ***** //********************************************************************** - bool standard_syrec_synthesizer::bitwise_negation(const std::vector& dest) { + bool SyrecSynthesis::bitwise_negation(const std::vector& dest) { for (unsigned idx: dest) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(idx); } return true; } - bool standard_syrec_synthesizer::decrement(const std::vector& dest) { + bool SyrecSynthesis::decrement(const std::vector& dest) { for (unsigned int i: dest) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(i); add_active_control(i); @@ -837,7 +510,7 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::increment(const std::vector& dest) { + bool SyrecSynthesis::increment(const std::vector& dest) { for (unsigned int i: dest) { add_active_control(i); } @@ -854,7 +527,7 @@ namespace syrec { //***** Binary Operations ***** //********************************************************************** - bool standard_syrec_synthesizer::bitwise_and(const std::vector& dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::bitwise_and(const std::vector& dest, const std::vector& src1, const std::vector& src2) { bool ok = true; for (unsigned i = 0u; i < dest.size(); ++i) { ok &= conjunction(dest.at(i), src1.at(i), src2.at(i)); @@ -862,14 +535,14 @@ namespace syrec { return ok; } - bool standard_syrec_synthesizer::bitwise_cnot(const std::vector& dest, const std::vector& src) { + bool SyrecSynthesis::bitwise_cnot(const std::vector& dest, const std::vector& src) { for (unsigned i = 0u; i < src.size(); ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src.at(i), dest.at(i)); } return true; } - bool standard_syrec_synthesizer::bitwise_or(const std::vector& dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::bitwise_or(const std::vector& dest, const std::vector& src1, const std::vector& src2) { bool ok = true; for (unsigned i = 0u; i < dest.size(); ++i) { ok &= disjunction(dest.at(i), src1.at(i), src2.at(i)); @@ -877,13 +550,13 @@ namespace syrec { return ok; } - bool standard_syrec_synthesizer::conjunction(unsigned dest, unsigned src1, unsigned src2) { + bool SyrecSynthesis::conjunction(unsigned dest, unsigned src1, unsigned src2) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_toffoli(src1, src2, dest); return true; } - bool standard_syrec_synthesizer::decrease_with_carry(const std::vector& dest, const std::vector& src, unsigned carry) { + bool SyrecSynthesis::decrease_with_carry(const std::vector& dest, const std::vector& src, unsigned carry) { for (unsigned i = 0u; i < src.size(); ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(dest.at(i)); } @@ -897,7 +570,7 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::disjunction(unsigned dest, unsigned src1, unsigned src2) { + bool SyrecSynthesis::disjunction(unsigned dest, unsigned src1, unsigned src2) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src1, dest); (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src2, dest); (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_toffoli(src1, src2, dest); @@ -905,7 +578,7 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::division(const std::vector& dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::division(const std::vector& dest, const std::vector& src1, const std::vector& src2) { if (!modulo(dest, src1, src2)) return false; std::vector sum; @@ -923,14 +596,14 @@ namespace syrec { partial.push_back(src2.at(src1.size() - 1u - i)); sum.insert(sum.begin(), src1.at(i)); add_active_control(dest.at(i)); - increase_new(sum, partial); + increase(sum, partial); remove_active_control(dest.at(i)); if (i > 0) { - for (unsigned j = (src1.size() - i); j < src1.size(); ++j) { + for (unsigned j = (static_cast(src1.size()) - i); j < src1.size(); ++j) { remove_active_control(src2.at(j)); } (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(src2.at(src1.size() - i)); - for (unsigned j = (src1.size() + 1u - i); j < src1.size(); ++j) { + for (unsigned j = (static_cast(src1.size()) + 1u - i); j < src1.size(); ++j) { add_active_control(src2.at(j)); } } @@ -939,7 +612,7 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::equals(unsigned dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::equals(unsigned dest, const std::vector& src1, const std::vector& src2) { for (unsigned i = 0u; i < src1.size(); ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src2.at(i), src1.at(i)); (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(src1.at(i)); @@ -956,46 +629,44 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::greater_equals(unsigned dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::greater_equals(unsigned dest, const std::vector& src1, const std::vector& src2) { if (!greater_than(dest, src2, src1)) return false; (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(dest); return true; } - bool standard_syrec_synthesizer::greater_than(unsigned dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::greater_than(unsigned dest, const std::vector& src1, const std::vector& src2) { return less_than(dest, src2, src1); } - bool standard_syrec_synthesizer::increase_new(const std::vector& rhs, const std::vector& lhs) { - unsigned bitwidth = rhs.size(); - - if (bitwidth == 1) { + bool SyrecSynthesis::increase(const std::vector& rhs, const std::vector& lhs) { + if (auto bitwidth = static_cast(rhs.size()); bitwidth == 1) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(lhs.at(0), rhs.at(0)); } else { - for (unsigned i = 1; i <= bitwidth - 1; ++i) { + for (int i = 1; i <= bitwidth - 1; ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(lhs.at(i), rhs.at(i)); } - for (unsigned i = bitwidth - 2; i >= 1; --i) { + for (int i = bitwidth - 2; i >= 1; --i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(lhs.at(i), lhs.at(i + 1)); } - for (unsigned i = 0; i <= bitwidth - 2; ++i) { + for (int i = 0; i <= bitwidth - 2; ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_toffoli(rhs.at(i), lhs.at(i), lhs.at(i + 1)); } (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(lhs.at(bitwidth - 1), rhs.at(bitwidth - 1)); - for (unsigned i = bitwidth - 2; i >= 1; --i) { + for (int i = bitwidth - 2; i >= 1; --i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_toffoli(lhs.at(i), rhs.at(i), lhs.at(i + 1)); (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(lhs.at(i), rhs.at(i)); } (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_toffoli(lhs.at(0), rhs.at(0), lhs.at(1)); (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(lhs.at(0), rhs.at(0)); - for (unsigned i = 1; i <= bitwidth - 2; ++i) { + for (int i = 1; i <= bitwidth - 2; ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(lhs.at(i), lhs.at(i + 1)); } - for (unsigned i = 1; i <= bitwidth - 1; ++i) { + for (int i = 1; i <= bitwidth - 1; ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(lhs.at(i), rhs.at(i)); } } @@ -1003,12 +674,12 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::decrease_new(const std::vector& rhs, const std::vector& lhs) { + bool SyrecSynthesis::decrease(const std::vector& rhs, const std::vector& lhs) { for (unsigned int rh: rhs) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(rh); } - increase_new(rhs, lhs); + increase(rhs, lhs); for (unsigned int rh: rhs) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(rh); @@ -1016,110 +687,55 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::decrease_new_assign(const std::vector& rhs, const std::vector& lhs) { - for (unsigned int lh: lhs) { - (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(lh); - } - - increase_new(rhs, lhs); - - for (unsigned int lh: lhs) { - (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(lh); - } - - for (unsigned i = 0u; i < lhs.size(); ++i) { - (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(rhs.at(i)); - } - return true; - } - - bool standard_syrec_synthesizer::expression_op_inverse(unsigned op, const std::vector& exp_lhs, const std::vector& exp_rhs) { - switch (op) { - case binary_expression::add: // + - decrease_new(exp_rhs, exp_lhs); - break; - case binary_expression::subtract: // - - decrease_new_assign(exp_rhs, exp_lhs); - break; - case binary_expression::exor: // ^ - bitwise_cnot(exp_rhs, exp_lhs); - break; - default: - return false; - } - return true; - } - - bool standard_syrec_synthesizer::expression_single_op(unsigned op, const std::vector& exp_lhs, const std::vector& exp_rhs) { - switch (op) { - case binary_expression::add: // + - increase_new(exp_rhs, exp_lhs); - break; - case binary_expression::subtract: // - - if (sub_flag) { - decrease_new_assign(exp_rhs, exp_lhs); - } else { - decrease_new(exp_rhs, exp_lhs); - } - break; - case binary_expression::exor: // ^ - bitwise_cnot(exp_rhs, exp_lhs); - break; - default: - return false; - } - return true; - } - - bool standard_syrec_synthesizer::increase_with_carry(const std::vector& dest, const std::vector& src, unsigned carry) { - unsigned bitwidth = src.size(); + bool SyrecSynthesis::increase_with_carry(const std::vector& dest, const std::vector& src, unsigned carry) { + auto bitwidth = static_cast(src.size()); if (bitwidth == 0) return true; - for (unsigned i = 1u; i < bitwidth; ++i) { + for (int i = 1u; i < bitwidth; ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src.at(i), dest.at(i)); } if (bitwidth > 1) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src.at(bitwidth - 1), carry); } - for (int i = (int)bitwidth - 2; i > 0; --i) { + for (int i = bitwidth - 2; i > 0; --i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src.at(i), src.at(i + 1)); } - for (unsigned i = 0u; i < bitwidth - 1; ++i) { + for (int i = 0u; i < bitwidth - 1; ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_toffoli(src.at(i), dest.at(i), src.at(i + 1)); } (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_toffoli(src.at(bitwidth - 1), dest.at(bitwidth - 1), carry); - for (int i = (int)bitwidth - 1; i > 0; --i) { + for (int i = bitwidth - 1; i > 0; --i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src.at(i), dest.at(i)); (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_toffoli(dest.at(i - 1), src.at(i - 1), src.at(i)); } - for (unsigned i = 1u; i < bitwidth - 1u; ++i) { + for (int i = 1u; i < bitwidth - 1; ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src.at(i), src.at(i + 1)); } - for (unsigned i = 0u; i < bitwidth; ++i) { + for (int i = 0u; i < bitwidth; ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src.at(i), dest.at(i)); } return true; } - bool standard_syrec_synthesizer::less_equals(unsigned dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::less_equals(unsigned dest, const std::vector& src1, const std::vector& src2) { if (!less_than(dest, src2, src1)) return false; (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(dest); return true; } - bool standard_syrec_synthesizer::less_than(unsigned dest, const std::vector& src1, const std::vector& src2) { - return (decrease_with_carry(src1, src2, dest) && increase_new(src1, src2)); + bool SyrecSynthesis::less_than(unsigned dest, const std::vector& src1, const std::vector& src2) { + return (decrease_with_carry(src1, src2, dest) && increase(src1, src2)); } - bool standard_syrec_synthesizer::modulo(const std::vector& dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::modulo(const std::vector& dest, const std::vector& src1, const std::vector& src2) { std::vector sum; std::vector partial; @@ -1136,15 +752,15 @@ namespace syrec { sum.insert(sum.begin(), src1.at(i)); decrease_with_carry(sum, partial, dest.at(i)); add_active_control(dest.at(i)); - increase_new(sum, partial); + increase(sum, partial); remove_active_control(dest.at(i)); (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(dest.at(i)); if (i > 0) { - for (unsigned j = (src1.size() - i); j < src1.size(); ++j) { + for (unsigned j = (static_cast(src1.size()) - i); j < src1.size(); ++j) { remove_active_control(src2.at(j)); } (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(src2.at(src1.size() - i)); - for (unsigned j = (src1.size() + 1u - i); j < src1.size(); ++j) { + for (unsigned j = (static_cast(src1.size()) + 1u - i); j < src1.size(); ++j) { add_active_control(src2.at(j)); } } @@ -1152,7 +768,7 @@ namespace syrec { return true; } - bool standard_syrec_synthesizer::multiplication(const std::vector& dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::multiplication(const std::vector& dest, const std::vector& src1, const std::vector& src2) { if ((src1.empty()) || (dest.empty())) return true; std::vector sum = dest; @@ -1168,20 +784,20 @@ namespace syrec { sum.erase(sum.begin()); partial.pop_back(); add_active_control(src1.at(i)); - ok = ok && increase_new(sum, partial); + ok = ok && increase(sum, partial); remove_active_control(src1.at(i)); } return ok; } - bool standard_syrec_synthesizer::not_equals(unsigned dest, const std::vector& src1, const std::vector& src2) { + bool SyrecSynthesis::not_equals(unsigned dest, const std::vector& src1, const std::vector& src2) { if (!equals(dest, src1, src2)) return false; (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(dest); return true; } - void standard_syrec_synthesizer::swap(const std::vector& dest1, const std::vector& dest2) { + void SyrecSynthesis::swap(const std::vector& dest1, const std::vector& dest2) { for (unsigned i = 0u; i < dest1.size(); ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_fredkin(dest1.at(i), dest2.at(i)); } @@ -1191,23 +807,26 @@ namespace syrec { //***** Shift Operations ***** //********************************************************************** - void standard_syrec_synthesizer::left_shift(const std::vector& dest, const std::vector& src1, unsigned src2) { + void SyrecSynthesis::left_shift(const std::vector& dest, const std::vector& src1, unsigned src2) { for (unsigned i = 0u; (i + src2) < dest.size(); ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src1.at(i), dest.at(i + src2)); } } - void standard_syrec_synthesizer::right_shift(const std::vector& dest, const std::vector& src1, unsigned src2) { + void SyrecSynthesis::right_shift(const std::vector& dest, const std::vector& src1, unsigned src2) { for (unsigned i = src2; i < dest.size(); ++i) { (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_cnot(src1.at(i), dest.at(i - src2)); } } + bool SyrecSynthesis::expression_op_inverse([[maybe_unused]] unsigned op, [[maybe_unused]] const std::vector& exp_lhs, [[maybe_unused]] const std::vector& exp_rhs) { + return true; + } //********************************************************************** //***** Efficient Controls ***** //********************************************************************** - void standard_syrec_synthesizer::add_active_control(unsigned control) { + void SyrecSynthesis::add_active_control(unsigned control) { // aktuelles Blatt vollendet, zurueck zum parent cct_man.current = source(*(in_edges(cct_man.current, cct_man.tree).first), cct_man.tree); @@ -1216,7 +835,6 @@ namespace syrec { get(boost::vertex_name, cct_man.tree)[child].control = control; get(boost::vertex_name, cct_man.tree)[child].controls = get(boost::vertex_name, cct_man.tree)[cct_man.current].controls; get(boost::vertex_name, cct_man.tree)[child].controls.insert(control); - // get( boost::vertex_name, cct_man.tree )[child].circ = std::shared_ptr( new circuit() ); add_edge(cct_man.current, child, cct_man.tree); cct_man.current = child; @@ -1229,7 +847,7 @@ namespace syrec { cct_man.current = leaf; } - void standard_syrec_synthesizer::remove_active_control(unsigned control [[maybe_unused]]) { + void SyrecSynthesis::remove_active_control(unsigned control [[maybe_unused]]) { // aktuelles Blatt vollendet, zurueck zum parent cct_man.current = source(*(in_edges(cct_man.current, cct_man.tree).first), cct_man.tree); @@ -1245,7 +863,7 @@ namespace syrec { cct_man.current = leaf; } - bool standard_syrec_synthesizer::assemble_circuit(const cct_node& current) { + bool SyrecSynthesis::assemble_circuit(const cct_node& current) { // leaf if (out_edges(current, cct_man.tree).first == out_edges(current, cct_man.tree).second /*get( boost::vertex_name, cct_man.tree )[current].circ.get()->num_gates() > 0u*/) { _circ.insert_circuit(_circ.num_gates(), *(get(boost::vertex_name, cct_man.tree)[current].circ), get(boost::vertex_name, cct_man.tree)[current].controls); @@ -1260,12 +878,12 @@ namespace syrec { return true; } - void standard_syrec_synthesizer::get_variables(const variable_access::ptr& var, std::vector& lines) { + void SyrecSynthesis::get_variables(const variable_access::ptr& var, std::vector& lines) { unsigned offset = _var_lines[var->get_var()]; if (!var->indexes.empty()) { // check if it is all numeric_expressions - unsigned n = var->get_var()->dimensions.size(); // dimensions + unsigned n = static_cast(var->get_var()->dimensions.size()); // dimensions if ((unsigned)std::count_if(var->indexes.cbegin(), var->indexes.cend(), [&](const auto& p) { return dynamic_cast(p.get()); }) == n) { for (unsigned i = 0u; i < n; ++i) { offset += dynamic_cast(var->indexes.at(i).get())->value->evaluate(loop_map) * @@ -1286,7 +904,7 @@ namespace syrec { lines.emplace_back(offset + i); } } else { - for (int i = (int)first; i >= (int)second; --i) { + for (auto i = static_cast(first); i >= static_cast(second); --i) { lines.emplace_back(offset + i); } } @@ -1308,7 +926,7 @@ namespace syrec { * \param bitwidth is the bitwidth of the variables within the array * \param lines is the destination, where */ - unsigned standard_syrec_synthesizer::get_constant_line(bool value) { + unsigned SyrecSynthesis::get_constant_line(bool value) { unsigned const_line = 0u; if (!free_const_lines_map[value].empty()) { @@ -1325,7 +943,7 @@ namespace syrec { return const_line; } - void standard_syrec_synthesizer::get_constant_lines(unsigned bitwidth, unsigned value, std::vector& lines) { + void SyrecSynthesis::get_constant_lines(unsigned bitwidth, unsigned value, std::vector& lines) { boost::dynamic_bitset<> number(bitwidth, value); for (unsigned i = 0u; i < bitwidth; ++i) { @@ -1333,8 +951,8 @@ namespace syrec { } } - void standard_syrec_synthesizer::add_variable(circuit& circ, const std::vector& dimensions, const variable::ptr& var, - constant _constant, bool _garbage, const std::string& arraystr) { + void SyrecSynthesis::add_variable(circuit& circ, const std::vector& dimensions, const variable::ptr& var, + constant _constant, bool _garbage, const std::string& arraystr) { if (dimensions.empty()) { for (unsigned i = 0u; i < var->bitwidth; ++i) { std::string name = var->name + arraystr + "." + std::to_string(i); @@ -1350,10 +968,10 @@ namespace syrec { } } - void standard_syrec_synthesizer::add_variables(circuit& circ, const variable::vec& variables) { + void SyrecSynthesis::add_variables(circuit& circ, const variable::vec& variables) { for (const auto& var: variables) { // entry in var lines map - _var_lines.insert(std::make_pair(var, circ.get_lines())); + _var_lines.try_emplace(var, circ.get_lines()); // types of constant and garbage constant _constant = (var->type == variable::out || var->type == variable::wire) ? constant(false) : constant(); @@ -1363,11 +981,17 @@ namespace syrec { } } - bool syrec_synthesis(circuit& circ, const program& program, const properties::ptr& settings, const properties::ptr& statistics) { + bool SyrecSynthesis::synthesize(SyrecSynthesis* synthesizer, circuit& circ, const program& program, const properties::ptr& settings, const properties::ptr& statistics) { // Settings parsing - auto variable_name_format = get(settings, "variable_name_format", "%1$s%3$s.%2$d"); - auto main_module = get(settings, "main_module", std::string()); - auto statement_synthesizer = standard_syrec_synthesizer(circ, program); + auto variable_name_format = get(settings, "variable_name_format", "%1$s%3$s.%2$d"); + auto main_module = get(settings, "main_module", std::string()); + // Run-time measuring + timer t; + + if (statistics) { + properties_timer rt(statistics); + t.start(rt); + } // get the main module module::ptr main; @@ -1386,27 +1010,14 @@ namespace syrec { } // declare as top module - statement_synthesizer.set_main_module(main); + synthesizer->set_main_module(main); // create lines for global variables - statement_synthesizer.add_variables(circ, main->parameters); - statement_synthesizer.add_variables(circ, main->variables); + synthesizer->add_variables(circ, main->parameters); + synthesizer->add_variables(circ, main->variables); - // Run-time measuring - timer t; - - if (statistics) { - properties_timer rt(statistics); - t.start(rt); - } // synthesize the statements - bool synth_okay = statement_synthesizer.on_module(main); - - if (statistics) { - t.stop(); - } - - return synth_okay; + return synthesizer->on_module(main); } } // namespace syrec diff --git a/src/algorithms/synthesis/syrec_synthesis_additional_lines.cpp b/src/algorithms/synthesis/syrec_synthesis_additional_lines.cpp new file mode 100644 index 00000000..5fe01caf --- /dev/null +++ b/src/algorithms/synthesis/syrec_synthesis_additional_lines.cpp @@ -0,0 +1,27 @@ +#include "algorithms/synthesis/syrec_synthesis_additional_lines.hpp" + +namespace syrec { + + void SyrecSynthesisAdditionalLines::exp_add(const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) { + SyrecSynthesis::get_constant_lines(bitwidth, 0u, lines); + SyrecSynthesis::bitwise_cnot(lines, lhs); // duplicate lhs + SyrecSynthesis::increase(lines, rhs); + } + + void SyrecSynthesisAdditionalLines::exp_subtract(const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) { + SyrecSynthesis::get_constant_lines(bitwidth, 0u, lines); + SyrecSynthesis::bitwise_cnot(lines, lhs); // duplicate lhs + SyrecSynthesis::decrease(lines, rhs); + } + + void SyrecSynthesisAdditionalLines::exp_exor(const unsigned& bitwidth, std::vector& lines, const std::vector& lhs, const std::vector& rhs) { + SyrecSynthesis::get_constant_lines(bitwidth, 0u, lines); + SyrecSynthesis::bitwise_cnot(lines, lhs); // duplicate lhs + SyrecSynthesis::bitwise_cnot(lines, rhs); + } + + bool SyrecSynthesisAdditionalLines::synthesize(circuit& circ, const program& program, const properties::ptr& settings, const properties::ptr& statistics) { + SyrecSynthesisAdditionalLines synthesizer(circ); + return SyrecSynthesis::synthesize(&synthesizer, circ, program, settings, statistics); + } +} // namespace syrec diff --git a/src/algorithms/synthesis/syrec_synthesis_no_additional_lines.cpp b/src/algorithms/synthesis/syrec_synthesis_no_additional_lines.cpp new file mode 100644 index 00000000..689c5f38 --- /dev/null +++ b/src/algorithms/synthesis/syrec_synthesis_no_additional_lines.cpp @@ -0,0 +1,383 @@ +#include "algorithms/synthesis/syrec_synthesis_no_additional_lines.hpp" + +namespace syrec { + /// checking the entire statement + bool SyrecSynthesisNoAdditionalLines::full_statement(const statement::ptr& statement) { + bool okay; + if (auto const* stat = dynamic_cast(statement.get())) { + okay = full_statement(*stat); + } else { + return false; + } + + return okay; + } + + bool SyrecSynthesisNoAdditionalLines::full_statement(const assign_statement& statement) { + std::vector d; + std::vector dd; + std::vector stat_lhs; + std::vector comp; + std::vector ddd; + std::vector lines; + get_variables(statement.lhs, stat_lhs); + + op_rhs_lhs_expression(statement.rhs, d); + + if (op_vec.empty()) { + return false; + } + flow(statement.rhs, ddd); + + /// Only when the rhs input signals are repeated (since the results are stored in the rhs) + + if (check_repeats()) { + flow(statement.rhs, dd); + + if (exp_op_vector.size() == 1) { + if (exp_op_vector.at(0) == 1 || exp_op_vector.at(0) == 2) { + /// cancel out the signals + + exp_op_vector.clear(); + assign_op_vector.clear(); + exp_lhs_vector.clear(); + exp_rhs_vector.clear(); + op_vec.clear(); + } else { + if (statement.op == 1) { + expression_single_op(1, exp_lhs_vector.at(0), stat_lhs); + expression_single_op(1, exp_rhs_vector.at(0), stat_lhs); + exp_op_vector.clear(); + assign_op_vector.clear(); + exp_lhs_vector.clear(); + exp_rhs_vector.clear(); + op_vec.clear(); + } else { + expression_single_op(statement.op, exp_lhs_vector.at(0), stat_lhs); + expression_single_op(exp_op_vector.at(0), exp_rhs_vector.at(0), stat_lhs); + exp_op_vector.clear(); + assign_op_vector.clear(); + exp_lhs_vector.clear(); + exp_rhs_vector.clear(); + op_vec.clear(); + } + } + + } else { + if (exp_lhs_vector.at(0) == exp_rhs_vector.at(0)) { + if (exp_op_vector.at(0) == 1 || exp_op_vector.at(0) == 2) { + /// cancel out the signals + } else if (exp_op_vector.at(0) != 1 || exp_op_vector.at(0) != 2) { + expression_single_op(statement.op, exp_lhs_vector.at(0), stat_lhs); + expression_single_op(exp_op_vector.at(0), exp_rhs_vector.at(0), stat_lhs); + } + } else { + solver(stat_lhs, statement.op, exp_lhs_vector.at(0), exp_op_vector.at(0), exp_rhs_vector.at(0)); + } + + unsigned j = 0; + unsigned z; + std::vector stat_assign_op; + if ((exp_op_vector.size() % 2) == 0) { + z = (static_cast(exp_op_vector.size()) / 2); + } else { + z = (static_cast((exp_op_vector.size()) - 1) / 2); + } + + for (unsigned k = 0; k <= z - 1; k++) { + stat_assign_op.push_back(assign_op_vector.at(k)); + } + + /// Assignment operations + + std::reverse(stat_assign_op.begin(), stat_assign_op.end()); + + /// If reversible assignment is "-", the assignment operations must negated appropriately + + if (statement.op == 1) { + for (unsigned int& i: stat_assign_op) { + if (i == 0) { + i = 1; + } else if (i == 1) { + i = 0; + } else { + continue; + } + } + } + + for (unsigned i = 1; i <= exp_op_vector.size() - 1; i++) { + /// when both rhs and lhs exist + if ((exp_lhs_vector.at(i) != comp) && (exp_rhs_vector.at(i) != comp)) { + if (exp_lhs_vector.at(i) == exp_rhs_vector.at(i)) { + if (exp_op_vector.at(i) == 1 || exp_op_vector.at(i) == 2) { + /// cancel out the signals + j = j + 1; + } else if (exp_op_vector.at(i) != 1 || exp_op_vector.at(i) != 2) { + if (stat_assign_op.at(j) == 1) { + expression_single_op(1, exp_lhs_vector.at(i), stat_lhs); + expression_single_op(1, exp_rhs_vector.at(i), stat_lhs); + j = j + 1; + } else { + expression_single_op(stat_assign_op.at(j), exp_lhs_vector.at(i), stat_lhs); + expression_single_op(exp_op_vector.at(i), exp_rhs_vector.at(i), stat_lhs); + j = j + 1; + } + } + } else { + solver(stat_lhs, stat_assign_op.at(j), exp_lhs_vector.at(i), exp_op_vector.at(i), exp_rhs_vector.at(i)); + j = j + 1; + } + } + + /// when only lhs exists o rhs exists + else if (((exp_lhs_vector.at(i) == comp) && (exp_rhs_vector.at(i) != comp)) || ((exp_lhs_vector.at(i) != comp) && (exp_rhs_vector.at(i) == comp))) { + exp_evaluate(lines, stat_assign_op.at(j), exp_rhs_vector.at(i), stat_lhs); + + j = j + 1; + } + } + exp_op_vector.clear(); + assign_op_vector.clear(); + exp_lhs_vector.clear(); + exp_rhs_vector.clear(); + op_vec.clear(); + } + } else { + exp_op_vector.clear(); + assign_op_vector.clear(); + exp_lhs_vector.clear(); + exp_rhs_vector.clear(); + op_vec.clear(); + return false; + } + + exp_op_vector.clear(); + assign_op_vector.clear(); + exp_lhs_vector.clear(); + exp_rhs_vector.clear(); + op_vec.clear(); + return true; + } + + bool SyrecSynthesisNoAdditionalLines::flow(const expression::ptr& expression, std::vector& v) { + if (auto const* binary = dynamic_cast(expression.get())) { + return flow(*binary, v); + } else if (auto const* var = dynamic_cast(expression.get())) { + return flow(*var, v); + } else { + return false; + } + } + + bool SyrecSynthesisNoAdditionalLines::flow(const variable_expression& expression, std::vector& v) { + get_variables(expression.var, v); + return true; + } + + /// generating LHS and RHS (can be whole expressions as well) + bool SyrecSynthesisNoAdditionalLines::flow(const binary_expression& expression, const std::vector& v [[maybe_unused]]) { + std::vector lhs; + std::vector rhs; + std::vector comp; + assign_op_vector.push_back(expression.op); + + if (!flow(expression.lhs, lhs) || !flow(expression.rhs, rhs)) { + return false; + } + + exp_lhs_vector.push_back(lhs); + exp_rhs_vector.push_back(rhs); + exp_op_vector.push_back(expression.op); + return true; + } + + bool SyrecSynthesisNoAdditionalLines::solver(const std::vector& stat_lhs, unsigned stat_op, const std::vector& exp_lhs, unsigned exp_op, const std::vector& exp_rhs) { + std::vector lines; + if (stat_op == exp_op) { + if (exp_op == 1) { + expression_single_op(1, exp_lhs, stat_lhs); + expression_single_op(0, exp_rhs, stat_lhs); + } else { + expression_single_op(stat_op, exp_lhs, stat_lhs); + expression_single_op(stat_op, exp_rhs, stat_lhs); + } + } else { + sub_flag = true; + exp_evaluate(lines, exp_op, exp_lhs, exp_rhs); + sub_flag = false; + exp_evaluate(lines, stat_op, lines, stat_lhs); + sub_flag = true; + if (exp_op < 3) { + expression_op_inverse(exp_op, exp_lhs, exp_rhs); + } + } + sub_flag = false; + return true; + } + + bool SyrecSynthesisNoAdditionalLines::op_rhs_lhs_expression(const expression::ptr& expression, std::vector& v) { + if (auto const* binary = dynamic_cast(expression.get())) { + return op_rhs_lhs_expression(*binary, v); + } else if (auto const* var = dynamic_cast(expression.get())) { + return op_rhs_lhs_expression(*var, v); + } else { + return false; + } + } + + bool SyrecSynthesisNoAdditionalLines::op_rhs_lhs_expression(const variable_expression& expression, std::vector& v) { + get_variables(expression.var, v); + return true; + } + + bool SyrecSynthesisNoAdditionalLines::op_rhs_lhs_expression(const binary_expression& expression, std::vector& v) { + std::vector lhs; + std::vector rhs; + + if (!op_rhs_lhs_expression(expression.lhs, lhs) || !op_rhs_lhs_expression(expression.rhs, rhs)) { + return false; + } + + v = rhs; + op_vec.push_back(expression.op); + return true; + } + + void SyrecSynthesisNoAdditionalLines::pop_exp() { + SyrecSynthesis::exp_opp.pop(); + SyrecSynthesis::exp_lhss.pop(); + SyrecSynthesis::exp_rhss.pop(); + } + + void SyrecSynthesisNoAdditionalLines::inverse() { + expression_op_inverse(SyrecSynthesis::exp_opp.top(), SyrecSynthesis::exp_lhss.top(), SyrecSynthesis::exp_rhss.top()); + SyrecSynthesis::sub_flag = false; + pop_exp(); + } + + void SyrecSynthesisNoAdditionalLines::assign_add(bool& status, std::vector& lhs, std::vector& rhs, const unsigned& op) { + if (!SyrecSynthesis::exp_opp.empty() && SyrecSynthesis::exp_opp.top() == op) { + SyrecSynthesis::increase(lhs, SyrecSynthesis::exp_lhss.top()); //status = bitwise_cnot(lhs, exp_lhss.top()) + status = SyrecSynthesis::increase(lhs, SyrecSynthesis::exp_rhss.top()); + pop_exp(); + } else { + status = SyrecSynthesis::increase(lhs, rhs); + } + while (!SyrecSynthesis::exp_opp.empty()) { + inverse(); + } + } + + void SyrecSynthesisNoAdditionalLines::assign_subtract(bool& status, std::vector& lhs, std::vector& rhs, const unsigned& op) { + if (!SyrecSynthesis::exp_opp.empty() && SyrecSynthesis::exp_opp.top() == op) { + SyrecSynthesis::decrease(lhs, SyrecSynthesis::exp_lhss.top()); //status = bitwise_cnot(lhs, exp_lhss.top()) + status = SyrecSynthesis::increase(lhs, SyrecSynthesis::exp_rhss.top()); + pop_exp(); + } else { + status = SyrecSynthesis::decrease(lhs, rhs); + } + while (!SyrecSynthesis::exp_opp.empty()) { + inverse(); + } + } + + void SyrecSynthesisNoAdditionalLines::assign_exor(bool& status, std::vector& lhs, std::vector& rhs, const unsigned& op) { + if (!SyrecSynthesis::exp_opp.empty() && SyrecSynthesis::exp_opp.top() == op) { + SyrecSynthesis::bitwise_cnot(lhs, SyrecSynthesis::exp_lhss.top()); //status = bitwise_cnot(lhs, exp_lhss.top()) + status = SyrecSynthesis::bitwise_cnot(lhs, SyrecSynthesis::exp_rhss.top()); + pop_exp(); + } else { + status = SyrecSynthesis::bitwise_cnot(lhs, rhs); + } + while (!SyrecSynthesis::exp_opp.empty()) { + inverse(); + } + } + /// This function is used when input signals (rhs) are equal (just to solve statements individually) + bool SyrecSynthesisNoAdditionalLines::exp_evaluate(std::vector& lines, unsigned op, const std::vector& lhs, const std::vector& rhs) { + switch (op) { + case binary_expression::add: // + + increase(rhs, lhs); + lines = rhs; + break; + case binary_expression::subtract: // - + if (sub_flag) { + decrease_new_assign(rhs, lhs); + lines = rhs; + } else { + decrease(rhs, lhs); + lines = rhs; + } + break; + case binary_expression::exor: // ^ + bitwise_cnot(rhs, lhs); // duplicate lhs + lines = rhs; + break; + default: + return false; + } + + return true; + } + + bool SyrecSynthesisNoAdditionalLines::decrease_new_assign(const std::vector& rhs, const std::vector& lhs) { + for (unsigned int lh: lhs) { + (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(lh); + } + + increase(rhs, lhs); + + for (unsigned int lh: lhs) { + (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(lh); + } + + for (unsigned i = 0u; i < lhs.size(); ++i) { + (*(get(boost::vertex_name, cct_man.tree)[cct_man.current].circ)).append_not(rhs.at(i)); + } + return true; + } + + bool SyrecSynthesisNoAdditionalLines::expression_single_op(unsigned op, const std::vector& exp_lhs, const std::vector& exp_rhs) { + switch (op) { + case binary_expression::add: // + + increase(exp_rhs, exp_lhs); + break; + case binary_expression::subtract: // - + if (sub_flag) { + decrease_new_assign(exp_rhs, exp_lhs); + } else { + decrease(exp_rhs, exp_lhs); + } + break; + case binary_expression::exor: // ^ + bitwise_cnot(exp_rhs, exp_lhs); + break; + default: + return false; + } + return true; + } + + bool SyrecSynthesisNoAdditionalLines::expression_op_inverse(unsigned op, const std::vector& exp_lhs, const std::vector& exp_rhs) { + switch (op) { + case binary_expression::add: // + + decrease(exp_rhs, exp_lhs); + break; + case binary_expression::subtract: // - + decrease_new_assign(exp_rhs, exp_lhs); + break; + case binary_expression::exor: // ^ + bitwise_cnot(exp_rhs, exp_lhs); + break; + default: + return false; + } + return true; + } + + bool SyrecSynthesisNoAdditionalLines::synthesize(circuit& circ, const program& program, const properties::ptr& settings, const properties::ptr& statistics) { + SyrecSynthesisNoAdditionalLines synthesizer(circ); + return SyrecSynthesis::synthesize(&synthesizer, circ, program, settings, statistics); + } +} // namespace syrec diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 232f1082..d5507cfc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,6 +30,8 @@ package_add_test(${PROJECT_NAME}_test unittests/test_parser.cpp unittests/test_synthesis.cpp unittests/test_simulation.cpp + unittests/test_add_lines_synthesis.cpp + unittests/test_add_lines_simulation.cpp unittests/test_tt_to_dd.cpp unittests/test_extend_tt.cpp unittests/test_huffman.cpp diff --git a/test/circuits/circuits_simulation_add_lines.json b/test/circuits/circuits_simulation_add_lines.json new file mode 100644 index 00000000..df019f2f --- /dev/null +++ b/test/circuits/circuits_simulation_add_lines.json @@ -0,0 +1,31 @@ +{ + "alu_2": { + "set_lines": [0,6], + "sim_out": "10100010100" + }, + + "swap_2": { + "set_lines": [2,3], + "sim_out": "1100" + }, + + "simple_add_2": { + "set_lines": [3], + "sim_out": "01010001" + }, + + "multiply_2": { + "set_lines": [3], + "sim_out": "00010000" + }, + + "modulo_2": { + "set_lines": [3,4,5], + "sim_out": "0101110100" + }, + + "negate_8": { + "set_lines": [6,7], + "sim_out": "00000011" + } +} diff --git a/test/circuits/circuits_synthesis_add_lines.json b/test/circuits/circuits_synthesis_add_lines.json new file mode 100644 index 00000000..bf570a98 --- /dev/null +++ b/test/circuits/circuits_synthesis_add_lines.json @@ -0,0 +1,207 @@ +{ + "alu_2": { + "num_gates": 26, + "lines": 11, + "quantum_costs" : 138, + "transistor_costs" : 384 + }, + + "binary_numeric": { + "num_gates": 30, + "lines": 60, + "quantum_costs" : 30, + "transistor_costs" : 240 + }, + + "bitwise_and_2": { + "num_gates": 8, + "lines": 8, + "quantum_costs" : 24, + "transistor_costs" : 96 + }, + + "bitwise_or_2": { + "num_gates": 12, + "lines": 8, + "quantum_costs" : 28, + "transistor_costs" : 128 + }, + + "bn_2": { + "num_gates": 188, + "lines": 74, + "quantum_costs" : 520, + "transistor_costs" : 1920 + }, + + "call_8": { + "num_gates": 212, + "lines": 41, + "quantum_costs" : 1492, + "transistor_costs" : 3776 + }, + + "divide_2": { + "num_gates": 252, + "lines": 22, + "quantum_costs" : 1076, + "transistor_costs" : 2832 + }, + + "for_4": + { + "num_gates" : 112, + "lines" : 41, + "quantum_costs" : 208, + "transistor_costs" : 1088 + }, + + "for_32": + { + "num_gates" : 2498, + "lines" : 641, + "quantum_costs" : 15426, + "transistor_costs" : 41856 + }, + + "gray_binary_conversion_16": + { + "num_gates" :94, + "lines" :63, + "quantum_costs" :462, + "transistor_costs" :1472 + }, + + "input_repeated_2": + { + "num_gates" :88, + "lines" :38, + "quantum_costs" :168, + "transistor_costs" :800 + }, + + "input_repeated_4": + { + "num_gates" :168, + "lines" :48, + "quantum_costs" :312, + "transistor_costs" :1504 + }, + + "logical_and_1": + { + "num_gates" :52, + "lines" :12, + "quantum_costs" :100, + "transistor_costs" :400 + }, + + "logical_or_1": + { + "num_gates" :53, + "lines" :12, + "quantum_costs" :101, + "transistor_costs" :416 + }, + + "modulo_2": + { + "num_gates" :31, + "lines" :10, + "quantum_costs" :111, + "transistor_costs" :320 + }, + + "multiple_statement_4": + { + "num_gates" :116, + "lines" :28, + "quantum_costs" :212, + "transistor_costs" :992 + }, + + "multiply_2": + { + "num_gates" :5, + "lines" :8, + "quantum_costs" :17, + "transistor_costs" :64 + }, + + + "negate_8": + { + "num_gates" :48, + "lines" :8, + "quantum_costs" :1740, + "transistor_costs" :896 + }, + + "numeric_2": + { + "num_gates" :34, + "lines" :68, + "quantum_costs" :34, + "transistor_costs" :272 + }, + + "operators_repeated_4": + { + "num_gates" :276, + "lines" :64, + "quantum_costs" :516, + "transistor_costs" :2496 + }, + + "parity_4": + { + "num_gates" :17, + "lines" :12, + "quantum_costs" :73, + "transistor_costs" :232 + }, + + "parity_check_16": + { + "num_gates" :69, + "lines" :51, + "quantum_costs" :333, + "transistor_costs" :1064 + }, + + "shift_4": { + "num_gates": 11, + "lines": 20, + "quantum_costs" : 11, + "transistor_costs" : 88 + }, + + "simple_add_2": { + "num_gates": 18, + "lines": 8, + "quantum_costs" : 34, + "transistor_costs" : 144 + }, + + "single_longstatement_4": { + "num_gates": 108, + "lines": 48, + "quantum_costs" : 180, + "transistor_costs" : 880 + }, + + "skip": { + "num_gates": 0, + "lines": 4, + "quantum_costs" : 0, + "transistor_costs" : 0 + }, + + "swap_2": { + "num_gates": 2, + "lines": 4, + "quantum_costs" : 2, + "transistor_costs" : 0 + } + +} diff --git a/test/python/test_syrec.py b/test/python/test_syrec.py index 457034bc..f7672bc3 100644 --- a/test/python/test_syrec.py +++ b/test/python/test_syrec.py @@ -2,55 +2,97 @@ import pytest import json -f_synthesis = open('../circuits/circuits_synthesis.json') -data_synthesis = json.load(f_synthesis) -f_synthesis.close() +f_synthesis_no_lines = open('../circuits/circuits_synthesis.json') +data_synthesis_no_lines = json.load(f_synthesis_no_lines) +f_synthesis_no_lines.close() -f_simulation = open('../circuits/circuits_simulation.json') -data_simulation = json.load(f_simulation) -f_simulation.close() +f_synthesis_add_lines = open('../circuits/circuits_synthesis_add_lines.json') +data_synthesis_add_lines = json.load(f_synthesis_add_lines) +f_synthesis_add_lines.close() -test_circuit_dir = "../circuits/" +f_simulation_no_lines = open('../circuits/circuits_simulation.json') +data_simulation_no_lines = json.load(f_simulation_no_lines) +f_simulation_no_lines.close() + +f_simulation_add_lines = open('../circuits/circuits_simulation_add_lines.json') +data_simulation_add_lines = json.load(f_simulation_add_lines) +f_simulation_add_lines.close() + +test_circuit_dir= "../circuits/" string_src = ".src" def test_parser(): - for file_name in data_synthesis: + for file_name in data_synthesis_no_lines: + prog = syrec.program() + error = prog.read(test_circuit_dir+ file_name + string_src) + + assert error == "" + + +def test_synthesis_no_lines(): + for file_name in data_synthesis_no_lines: + circ = syrec.circuit() + prog = syrec.program() + error = prog.read(test_circuit_dir+ file_name + string_src) + + assert error == "" + assert syrec.syrec_synthesis_no_additional_lines(circ, prog) + assert data_synthesis_no_lines[file_name]["num_gates"] == circ.num_gates + assert data_synthesis_no_lines[file_name]["lines"] == circ.lines + assert data_synthesis_no_lines[file_name]["quantum_costs"] == circ.quantum_cost() + assert data_synthesis_no_lines[file_name]["transistor_costs"] == circ.transistor_cost() + +def test_synthesis_add_lines(): + for file_name in data_synthesis_add_lines: + circ = syrec.circuit() prog = syrec.program() - error = prog.read(test_circuit_dir + file_name + string_src) + error = prog.read(test_circuit_dir+ file_name + string_src) assert error == "" + assert syrec.syrec_synthesis_additional_lines(circ, prog) + assert data_synthesis_add_lines[file_name]["num_gates"] == circ.num_gates + assert data_synthesis_add_lines[file_name]["lines"] == circ.lines + assert data_synthesis_add_lines[file_name]["quantum_costs"] == circ.quantum_cost() + assert data_synthesis_add_lines[file_name]["transistor_costs"] == circ.transistor_cost() -def test_synthesis(): - for file_name in data_synthesis: +def test_simulation_no_lines(): + for file_name in data_simulation_no_lines: circ = syrec.circuit() prog = syrec.program() - error = prog.read(test_circuit_dir + file_name + string_src) + error = prog.read(test_circuit_dir+ file_name + string_src) assert error == "" - assert syrec.synthesis(circ, prog) - assert data_synthesis[file_name]["num_gates"] == circ.num_gates - assert data_synthesis[file_name]["lines"] == circ.lines - assert data_synthesis[file_name]["quantum_costs"] == circ.quantum_cost() - assert data_synthesis[file_name]["transistor_costs"] == circ.transistor_cost() + assert syrec.syrec_synthesis_no_additional_lines(circ, prog) + + my_inp_bitset = syrec.bitset(circ.lines) + my_out_bitset = syrec.bitset(circ.lines) + set_list = data_simulation_no_lines[file_name]["set_lines"] + + for set_index in set_list: + my_inp_bitset.set(set_index, True) + + syrec.simple_simulation(my_out_bitset, circ, my_inp_bitset) + assert data_simulation_no_lines[file_name]["sim_out"] == str(my_out_bitset) + -def test_simulation(): - for file_name in data_simulation: +def test_simulation_add_lines(): + for file_name in data_simulation_add_lines: circ = syrec.circuit() prog = syrec.program() - error = prog.read(test_circuit_dir + file_name + string_src) + error = prog.read(test_circuit_dir+ file_name + string_src) assert error == "" - assert syrec.synthesis(circ, prog) + assert syrec.syrec_synthesis_additional_lines(circ, prog) my_inp_bitset = syrec.bitset(circ.lines) my_out_bitset = syrec.bitset(circ.lines) - set_list = data_simulation[file_name]["set_lines"] + set_list = data_simulation_add_lines[file_name]["set_lines"] for set_index in set_list: my_inp_bitset.set(set_index, True) syrec.simple_simulation(my_out_bitset, circ, my_inp_bitset) - assert data_simulation[file_name]["sim_out"] == str(my_out_bitset) + assert data_simulation_add_lines[file_name]["sim_out"] == str(my_out_bitset) diff --git a/test/unittests/test_add_lines_simulation.cpp b/test/unittests/test_add_lines_simulation.cpp new file mode 100644 index 00000000..17eda341 --- /dev/null +++ b/test/unittests/test_add_lines_simulation.cpp @@ -0,0 +1,76 @@ +#include "algorithms/simulation/simple_simulation.hpp" +#include "algorithms/synthesis/syrec_synthesis_additional_lines.hpp" +#include "core/circuit.hpp" +#include "core/properties.hpp" +#include "core/syrec/program.hpp" + +#include "gtest/gtest.h" +#include +#include +#include +#include +#include + +using json = nlohmann::json; + +using namespace syrec; + +class SyrecAddLinesSimulationTest: public testing::TestWithParam { +protected: + std::string test_circuits_dir = "./circuits/"; + std::string file_name; + boost::dynamic_bitset<> input; + boost::dynamic_bitset<> output; + std::vector set_lines; + std::string expected_sim_out; + std::string output_string; + + void SetUp() override { + std::string synthesis_param = GetParam(); + file_name = test_circuits_dir + GetParam() + ".src"; + std::ifstream i(test_circuits_dir + "circuits_simulation_add_lines.json"); + json j = json::parse(i); + expected_sim_out = j[synthesis_param]["sim_out"]; + set_lines = j[synthesis_param]["set_lines"].get>(); + } +}; + +INSTANTIATE_TEST_SUITE_P(SyrecSimulationTest, SyrecAddLinesSimulationTest, + testing::Values( + "alu_2", + "swap_2", + "simple_add_2", + "multiply_2", + "modulo_2", + "negate_8"), + [](const testing::TestParamInfo& info) { + auto s = info.param; + std::replace( s.begin(), s.end(), '-', '_'); + return s; }); + +TEST_P(SyrecAddLinesSimulationTest, GenericSimulationTest) { + circuit circ; + program prog; + read_program_settings settings; + properties::ptr statistics; + std::string error_string; + + error_string = prog.read(file_name, settings); + EXPECT_TRUE(error_string.empty()); + + EXPECT_TRUE(SyrecSynthesisAdditionalLines::synthesize(circ, prog)); + + input.resize(circ.get_lines()); + + for (int line: set_lines) + input.set(line); + + output.resize(circ.get_lines()); + + simple_simulation(output, circ, input, statistics); + + boost::to_string(output, output_string); + std::reverse(output_string.begin(), output_string.end()); + + EXPECT_EQ(expected_sim_out, output_string); +} diff --git a/test/unittests/test_add_lines_synthesis.cpp b/test/unittests/test_add_lines_synthesis.cpp new file mode 100644 index 00000000..98bcf6f1 --- /dev/null +++ b/test/unittests/test_add_lines_synthesis.cpp @@ -0,0 +1,89 @@ +#include "algorithms/synthesis/syrec_synthesis_additional_lines.hpp" +#include "core/circuit.hpp" +#include "core/properties.hpp" +#include "core/syrec/program.hpp" + +#include "gtest/gtest.h" +#include +#include +#include + +using json = nlohmann::json; + +using namespace syrec; + +class SyrecAddLinesSynthesisTest: public testing::TestWithParam { +protected: + std::string test_circuits_dir = "./circuits/"; + std::string file_name; + gate::cost_t qc = 0; + gate::cost_t tc = 0; + unsigned expected_num_gates = 0; + unsigned expected_lines = 0; + gate::cost_t expected_qc = 0; + gate::cost_t expected_tc = 0; + + void SetUp() override { + std::string synthesis_param = GetParam(); + file_name = test_circuits_dir + GetParam() + ".src"; + std::ifstream i(test_circuits_dir + "circuits_synthesis_add_lines.json"); + json j = json::parse(i); + expected_num_gates = j[synthesis_param]["num_gates"]; + expected_lines = j[synthesis_param]["lines"]; + expected_qc = j[synthesis_param]["quantum_costs"]; + expected_tc = j[synthesis_param]["transistor_costs"]; + } +}; + +INSTANTIATE_TEST_SUITE_P(SyrecSynthesisTest, SyrecAddLinesSynthesisTest, + testing::Values( + "alu_2", + "binary_numeric", + "bitwise_and_2", + "bitwise_or_2", + "bn_2", + "call_8", + "divide_2", + "for_4", + "for_32", + "gray_binary_conversion_16", + "input_repeated_2", + "input_repeated_4", + "logical_and_1", + "logical_or_1", + "modulo_2", + "multiply_2", + "negate_8", + "numeric_2", + "operators_repeated_4", + "parity_4", + "parity_check_16", + "shift_4", + "simple_add_2", + "single_longstatement_4", + "skip", + "swap_2"), + [](const testing::TestParamInfo& info) { + auto s = info.param; + std::replace( s.begin(), s.end(), '-', '_'); + return s; }); + +TEST_P(SyrecAddLinesSynthesisTest, GenericSynthesisTest) { + circuit circ; + program prog; + read_program_settings settings; + std::string error_string; + + error_string = prog.read(file_name, settings); + EXPECT_TRUE(error_string.empty()); + + EXPECT_TRUE(SyrecSynthesisAdditionalLines::synthesize(circ, prog)); + + qc = circ.quantum_cost(); + tc = circ.transistor_cost(); + + EXPECT_EQ(expected_num_gates, circ.num_gates()); + EXPECT_EQ(expected_lines, circ.get_lines()); + EXPECT_EQ(expected_qc, qc); + EXPECT_EQ(expected_tc, tc); +} diff --git a/test/unittests/test_simulation.cpp b/test/unittests/test_simulation.cpp index d28ce27e..f0244332 100644 --- a/test/unittests/test_simulation.cpp +++ b/test/unittests/test_simulation.cpp @@ -1,5 +1,5 @@ #include "algorithms/simulation/simple_simulation.hpp" -#include "algorithms/synthesis/syrec_synthesis.hpp" +#include "algorithms/synthesis/syrec_synthesis_no_additional_lines.hpp" #include "core/circuit.hpp" #include "core/properties.hpp" #include "core/syrec/program.hpp" @@ -58,7 +58,7 @@ TEST_P(SyrecSimulationTest, GenericSimulationTest) { error_string = prog.read(file_name, settings); EXPECT_TRUE(error_string.empty()); - EXPECT_TRUE(syrec_synthesis(circ, prog)); + EXPECT_TRUE(SyrecSynthesisNoAdditionalLines::synthesize(circ, prog)); input.resize(circ.get_lines()); diff --git a/test/unittests/test_synthesis.cpp b/test/unittests/test_synthesis.cpp index 194c54f3..c5bf75d4 100644 --- a/test/unittests/test_synthesis.cpp +++ b/test/unittests/test_synthesis.cpp @@ -1,4 +1,4 @@ -#include "algorithms/synthesis/syrec_synthesis.hpp" +#include "algorithms/synthesis/syrec_synthesis_no_additional_lines.hpp" #include "core/circuit.hpp" #include "core/properties.hpp" #include "core/syrec/program.hpp" @@ -77,7 +77,7 @@ TEST_P(SyrecSynthesisTest, GenericSynthesisTest) { error_string = prog.read(file_name, settings); EXPECT_TRUE(error_string.empty()); - EXPECT_TRUE(syrec_synthesis(circ, prog)); + EXPECT_TRUE(SyrecSynthesisNoAdditionalLines::synthesize(circ, prog)); qc = circ.quantum_cost(); tc = circ.transistor_cost();