diff --git a/.gitignore b/.gitignore index 61875b9..861889c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ +docs/ +benchmarks/ temp/ build/ compile_commands.json out/ include/bbdd/ *.csv diff --git a/CMakeLists.txt b/CMakeLists.txt index d14ef81..f89ec44 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,52 +1,92 @@ cmake_minimum_required(VERSION 3.8) project(mockturtle LANGUAGES CXX) set(MOCKTURTLE_CXX_STANDARD "17" CACHE STRING "C++ standard") set(CMAKE_CXX_STANDARD ${MOCKTURTLE_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Options option(MOCKTURTLE_EXAMPLES "Build examples" ON) option(MOCKTURTLE_TEST "Build tests" OFF) option(MOCKTURTLE_EXPERIMENTS "Build experiments" OFF) option(BILL_Z3 "Enable Z3 interface for bill library" OFF) option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang" OFF) option(ENABLE_MATPLOTLIB "Enable matplotlib library in experiments" OFF) option(ENABLE_NAUTY "Enable the Nauty library for percy" OFF) option(ENABLE_ABC "Enable linking ABC as a static library" OFF) option(ENABLE_CACHE_STATS "Enable cache stats" OFF) if(UNIX) # show quite some warnings (but remove some intentionally) include(CheckCXXCompilerFlag) add_compile_options(-W -Wall -Wextra) foreach (WARNING unknown-pragmas gnu-anonymous-struct nested-anon-types) check_cxx_compiler_flag("-Wno-${WARNING}" HAS_WNO_${WARNING}) if (HAS_WNO_${WARNING}) add_compile_options(-Wno-${WARNING}) endif() endforeach() if (ENABLE_COVERAGE) add_compile_options(-O0 -g --coverage -fprofile-arcs -ftest-coverage) endif() endif() if(MSVC) add_compile_options(/EHsc /bigobj) endif() if (WIN32) set(ENABLE_NAUTY OFF) endif() add_subdirectory(include) add_subdirectory(lib) add_subdirectory(src) if(ENABLE_NAUTY) add_definitions(-DENABLE_NAUTY) endif() if (ENABLE_ABC) if (NOT EXISTS ${PROJECT_SOURCE_DIR}/lib/abc_static/libabc.a) message(FATAL_ERROR "Cannot find libabc.a in lib/abc_static/. For more info, see https://github.com/lsils/abc-staticlib") endif() endif() + +############################################# Generate Doxygen Documentation +# Option to build docs +option(BUILD_DOC "Build API documentation with Doxygen" ON) + +if(BUILD_DOC) + find_package(Doxygen QUIET) + + if(NOT DOXYGEN_FOUND) + message(WARNING "Doxygen not found. Set BUILD_DOC=OFF or install Doxygen.") + else() + # Graphviz (dot) for diagrams — optional + find_program(DOT_EXE dot) + set(DOXYGEN_HAVE_DOT "NO") + if(DOT_EXE) + set(DOXYGEN_HAVE_DOT "YES") + endif() + + configure_file( + "${CMAKE_SOURCE_DIR}/Doxyfile.in" + "${CMAKE_BINARY_DIR}/Doxyfile" + @ONLY + ) + + # docs target + add_custom_target(docs + COMMAND "${DOXYGEN_EXECUTABLE}" "${CMAKE_BINARY_DIR}/Doxyfile" + WORKING_DIRECTORY "${CMAKE_BINARY_DIR}" + COMMENT "Generating API documentation with Doxygen" + VERBATIM + ) + + # Optional: convenience target to clean generated docs + add_custom_target(docs-clean + COMMAND "${CMAKE_COMMAND}" -E rm -rf "${DOXYGEN_OUTPUT_DIR}" + COMMENT "Removing generated documentation in ${DOXYGEN_OUTPUT_DIR}" + VERBATIM + ) + endif() +endif() diff --git a/Doxyfile.in b/Doxyfile.in new file mode 100644 index 0000000..1066851 --- /dev/null +++ b/Doxyfile.in @@ -0,0 +1,38 @@ +# ---------- Project ---------- +PROJECT_NAME = "NEM synthesis project" +OUTPUT_DIRECTORY = "../docs" +FULL_PATH_NAMES = NO +OPTIMIZE_OUTPUT_FOR_CPLUSPLUS = YES + +# ---------- Inputs ---------- +INPUT = "../include" +RECURSIVE = YES +FILE_PATTERNS = *.hpp + +# Parse Doxygen/Javadoc-style comments +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +JAVADOC_AUTOBRIEF = YES + +# ---------- Warnings ---------- +WARN_IF_UNDOCUMENTED = YES +WARN_AS_ERROR = NO + +# ---------- HTML ---------- +GENERATE_HTML = YES +HTML_OUTPUT = html +GENERATE_TREEVIEW = YES + +# ---------- Diagrams (Graphviz) ---------- +HAVE_DOT = @DOXYGEN_HAVE_DOT@ +DOT_IMAGE_FORMAT = svg +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES + +# ---------- Misc ---------- +GENERATE_LATEX = NO +GENERATE_XML = NO + diff --git a/include/bbdd b/include/bbdd index 180fb5f..47b08d4 160000 --- a/include/bbdd +++ b/include/bbdd @@ -1 +1 @@ -Subproject commit 180fb5f785ecbb27d7b94125ab39d238afb7c9e1 +Subproject commit 47b08d44edeec62656360fa3394861686a849ad0 diff --git a/include/util/cover_to_bbdd.hpp b/include/util/cover_to_bbdd.hpp index 9cffedb..8bc8252 100644 --- a/include/util/cover_to_bbdd.hpp +++ b/include/util/cover_to_bbdd.hpp @@ -1,149 +1,164 @@ +// Copyright 2025 Oliver Theimer #pragma once +#include +#include #include "../bbdd/include/bbdd.hpp" #include "../bbdd/include/bbdd_node.hpp" -#include "mockturtle/traits.hpp" #include "../bbdd/include/unique_table.hpp" +#include "mockturtle/traits.hpp" #include "util.hpp" -#include -#include #define LEFT_CHILD(node) node.children[0].index #define RIGHT_CHILD(node) node.children[1].index #define CUBE(node) ntk._storage->data.covers[node.data[1].h1] int nodes_visited; using namespace mockturtle; +/** + * @brief recursively creates a bbdd based on the given network + * + * @tparam Ntk template for which network type is used + * @param table unique table in which the bbdd should be stored in + * @param ntk input network data structure that should be converted + * @param node_i starting node from which onwards the bbdd should be created, + * will be used for the recursion + * @param output_completed statistics that are used in the recursion to properly + * show the progress bar + * @return root node of the created bbdd + */ template -bbdd_node_t *create_bbdd(Unique_table *table, Ntk &ntk, const auto &node_i, - int output_completed) { +static bbdd_node_t *create_bbdd(Unique_table *table, Ntk &ntk, + const auto &node_i, int output_completed) { static_assert(has_is_ci_v, "Ntk does not implement the is_ci method"); const auto &node = ntk._storage->nodes[node_i]; bbdd_node_t *f, *g, *result; bbdd_op_t op = Util::cube_to_bbdd_op(CUBE(node)); if (ntk.visited(node_i)) { return table->get_node_p(ntk.visited(node_i)); } #ifdef DEBUG_COVER printf("[INFO] CREATE: node %d with op %s\n", node_i, bbdd_op_s[op].c_str()); #endif if (node.children.size() != 2 && node.children.size() != 1) { if (node_i == 1 || node_i == 0) { return table->get_node_p(node_i); } #ifdef DEBUG_COVER std::cout << node_i << ": " << node.children.size() << " with " << bbdd_op_s[op].c_str() << "\n"; #endif assert(ntk.is_ci(node_i)); assert(node_i < pow(2, 31)); assert(node_i - 2 < ntk._storage->inputs.size()); return table->insert_node({{(node_index_t)node_i, INT_MAX}, 0, 1}); } assert(node.children.size() == 2 || node.children.size() == 1); // all the logic gates except buf and inv if (node.children.size() == 2) { node_index_t f_i = LEFT_CHILD(node), g_i = RIGHT_CHILD(node); if (ntk.is_ci(LEFT_CHILD(node)) && ntk.is_ci(RIGHT_CHILD(node))) { result = base_case_two_inputs(table, f_i, g_i, op); #ifdef DEBUG_COVER printf("[INFO] CREATE: two input case %d: %d %s %d\n", result->index, f_i, bbdd_op_s[op].c_str(), g_i); #endif return result; } f = create_bbdd(table, ntk, LEFT_CHILD(node), output_completed); g = create_bbdd(table, ntk, RIGHT_CHILD(node), output_completed); result = merge_bbdds(table, f, g, op); #ifdef DEBUG_COVER std::cout << "[INFO] CREATE: merging " << result->index << ": " << f->index << " " << bbdd_op_s[op] << " " << g->index << "\n"; dump_node(g); #endif ntk.set_visited(node_i, result->index); Util::show_progress_bar( {{"Output", {output_completed, ntk._storage->outputs.size()}}, {"Nodes", {++nodes_visited, ntk._storage->nodes.size()}}}, 50); return result; } else { // buf and inverter nodes f = create_bbdd(table, ntk, LEFT_CHILD(node), output_completed); if (op == bbdd_inv) { result = negate_recursive(table, f); ntk.set_visited(node_i, result->index); Util::show_progress_bar( {{"Output", {output_completed, ntk._storage->outputs.size()}}, {"Nodes", {++nodes_visited, ntk._storage->nodes.size()}}}, 50); return result; } ntk.set_visited(node_i, f->index); Util::show_progress_bar( {{"Output", {output_completed, ntk._storage->outputs.size()}}, {"Nodes", {++nodes_visited, ntk._storage->nodes.size()}}}, 50); return f; } } +/** + * @brief main conversion function that should be used as an interface, it + * interact with the recursive function, instantiates the progress bar and + * registers output in the unique table + * + * @tparam Ntk template of network type that should be used + * @param table unique table in which the data structure should be stores + * @param ntk data strucutre that stores the input network type which should be + * converted + * @param use_height if true the height of the bbdd is used as the target + * function for the sifting algorithm, otherwise the number of nodes i used + * @param sifting_repetitions indicates how often the sifting algorithm should be repeated at the end of the conversion + */ template void cover_to_bbdd(Unique_table *table, Ntk &ntk, bool use_height, - int sifting_repetitions, std::ofstream &order_file) { + int sifting_repetitions) { static_assert(has_foreach_co_v, "Ntk does not implement the foreach_pi method"); static_assert(has_get_node_v, "Ntk does not implement the get_node method"); static_assert(has_set_visited_v, "Ntk does not implement the set_visited method"); static_assert(has_visited_v, "Ntk does not implement the set_visited method"); int index = ntk._storage->inputs.size() + 2; int output_completed = 0; nodes_visited = 0; Util::show_progress_bar( {{"Output", {output_completed, ntk._storage->outputs.size()}}, {"Nodes", {++nodes_visited, ntk._storage->nodes.size()}}}, 50); - ntk.foreach_co([ntk, &table, &index, &output_completed, sifting_repetitions](const auto &node_i) { + ntk.foreach_co([ntk, &table, &index, &output_completed, + sifting_repetitions](const auto &node_i) { const auto &node = ntk.get_node(node_i); auto &n = ntk._storage->nodes[node_i]; #ifdef DEBUG_COVER std::cout << "output with node_i: " << node_i << " and n->index: " << " : " << n.children.size() << "\n"; #endif bbdd_node_t *output = add_ref(create_bbdd(table, ntk, node, output_completed)); Util::show_progress_bar( {{"Output", {++output_completed, ntk._storage->outputs.size()}}, {"Nodes", {++nodes_visited, ntk._storage->nodes.size()}}}, 50); table->add_output(ntk.get_signal_name(index), output); index++; - /*if (table->get_total_height() > 20 && table->get_total_height() < 30) { - sift(table, &Unique_table::get_total_number_nodes, table); - ntk.clear_visited(); - }*/ }); for (int i = 0; i < sifting_repetitions; i++) { - /*printf("total height before sifting: %d and total number of nodes before: " - "%d\n", - table->get_max_height(), table->get_total_number_nodes()); - if (order_file.is_open()) { - dump_ordering(table->cvo, order_file); - order_file << ";" << table->get_max_height() << ";" - << table->get_total_number_nodes() << "\n"; - }*/ if (table->get_total_height() < 30) { if (use_height) { sift(table, &Unique_table::get_total_height, table); } else { sift(table, &Unique_table::get_total_number_nodes, table); } } } } diff --git a/include/util/cover_to_bdd.hpp b/include/util/cover_to_bdd.hpp index dc444e1..c9be00d 100644 --- a/include/util/cover_to_bdd.hpp +++ b/include/util/cover_to_bdd.hpp @@ -1,114 +1,133 @@ +// Copyright 2025 Oliver Theimer #pragma once #include "../bbdd/include/bbdd_node.hpp" #include "bdd.h" #include "util.hpp" #define LEFT_CHILD(node) node.children[0].index #define RIGHT_CHILD(node) node.children[1].index #define CUBE(node) ntk._storage->data.covers[node.data[1].h1] using namespace mockturtle; -template bdd create_bdd(Ntk &ntk, const auto &node_i) { +/** + * @brief recursively creates a bdd based on the given network + * + * @tparam Ntk which network type is used as an input to the function + * @param ntk input network which should be converted to bdd + * @param node_i current network node which is currently converted is used for + * the recursion + * @return return root bdd node of the created binary decision diagram + */ +template static bdd create_bdd(Ntk &ntk, const auto &node_i) { static_assert(has_is_ci_v, "Ntk does not implement the is_ci method"); const auto &node = ntk._storage->nodes[node_i]; bdd f, g, result; bbdd_op_t op = Util::cube_to_bbdd_op(CUBE(node)); if (node.children.size() != 2 && node.children.size() != 1) { if (node_i == 1) { #ifdef DEBUG_BDD printf("[INFO] cover to bdd: constant 1 node\n"); #endif return bdd_true(); } if (node_i == 0) { #ifdef DEBUG_BDD printf("[INFO] cover to bdd: constant 0 node\n"); #endif return bdd_false(); } assert(ntk.is_ci(node_i)); assert(node_i < pow(2, 31)); assert(node_i - 2 < ntk._storage->inputs.size()); #ifdef DEBUG_BDD printf("[INFO] cover to bdd: base case input: %d\n", node_i); #endif return bdd_ithvar(node_i - 2); } assert(node.children.size() == 2 || node.children.size() == 1); // all the logic gates except buf and inv if (node.children.size() == 2) { node_index_t f_i = LEFT_CHILD(node), g_i = RIGHT_CHILD(node); f = create_bdd(ntk, LEFT_CHILD(node)); #ifdef DEBUG_BDD printf("[INFO] cover to bdd: return from f\n"); #endif g = create_bdd(ntk, RIGHT_CHILD(node)); #ifdef DEBUG_BDD - printf("[INFO] cover to bdd: merge %d %s %d\n", f, - bbdd_op_s[op].c_str(), g); + printf("[INFO] cover to bdd: merge %d %s %d\n", f, bbdd_op_s[op].c_str(), + g); #endif switch (op) { case bbdd_and: result = bdd_apply(f, g, bddop_and); break; case bbdd_xor: result = bdd_apply(f, g, bddop_xor); break; case bbdd_xnor: result = bdd_not(bdd_apply(f, g, bddop_xor)); break; case bbdd_or: result = bdd_apply(f, g, bddop_or); break; case bbdd_nand: result = bdd_apply(f, g, bddop_nand); break; case bbdd_nor: result = bdd_apply(f, g, bddop_nor); break; default: printf("%s\n", bbdd_op_s[op].c_str()); assert(false && "not implemented yet"); break; } return result; } else { // buf and inverter nodes f = create_bdd(ntk, LEFT_CHILD(node)); // TODO how to invert if (op == bbdd_inv) { #ifdef DEBUG_BDD printf("[INFO] cover to bdd: negate\n"); #endif result = bdd_not(f); return result; } #ifdef DEBUG_BDD printf("[INFO] cover to bdd: buffer\n"); #endif return f; } } -template void cover_to_bdd(Ntk &ntk, std::vector> &output_map) { +/** + * @brief main interface function that handles the conversion to a bdd from a given input network type + * + * @tparam Ntk network type that is used as an input to the conversion + * @param ntk network that should be converted to a bdd + * @param output_map outputmap that stores the pointers to the root nodes of each output in the network + */ +template +void cover_to_bdd(Ntk &ntk, + std::vector> &output_map) { static_assert(has_foreach_co_v, "Ntk does not implement the foreach_pi method"); static_assert(has_get_node_v, "Ntk does not implement the get_node method"); static_assert(has_set_visited_v, "Ntk does not implement the set_visited method"); static_assert(has_visited_v, "Ntk does not implement the set_visited method"); int index = ntk._storage->inputs.size() + 2; ntk.foreach_co([ntk, &index, &output_map](const auto &node_i) { const auto &node = ntk.get_node(node_i); auto &n = ntk._storage->nodes[node_i]; bdd output = create_bdd(ntk, node); output_map.emplace_back(output, ntk.get_signal_name(index)); bdd_printtable(output); index++; }); - } +} diff --git a/include/util/util.hpp b/include/util/util.hpp index d2aec2b..450bcb9 100644 --- a/include/util/util.hpp +++ b/include/util/util.hpp @@ -1,97 +1,118 @@ +// Copyright 2025 Oliver Theimer +#pragma once +#include +#include +#include +#include +#include + #include "../bbdd/include/bbdd_node.hpp" #include "kitty/cube.hpp" #include "mockturtle/networks/cover.hpp" -#include #include #include -#include class Util { - -public: + public: + /** + * @brief converts cover node to boolean function information + * + * @param cover cover node that stores the cubes + * @return the represented boolean function of the cubes + */ static bbdd_op_t cube_to_bbdd_op(std::pair, bool> const &cover) { bbdd_op_t type = bbdd_none; - if (cover.second) { // on-set + // on-set + if (cover.second) { if (cover.first.size() == 1) { if (cover.first[0] == kitty::cube("11")) { type = bbdd_and; } else if (cover.first[0] == kitty::cube("0")) { type = bbdd_inv; } else if (cover.first[0] == kitty::cube("00")) { type = bbdd_and; } else if (cover.first[0] == kitty::cube("01")) { type = bbdd_notand; } else if (cover.first[0] == kitty::cube("10")) { type = bbdd_andnot; } else if (cover.first[0] == kitty::cube("1")) { type = bbdd_buf; } else if (cover.first[0] == kitty::cube("")) { type = bbdd_one; } } else if (cover.first.size() == 2) { if (cover.first[0] == kitty::cube("1-") && cover.first[1] == kitty::cube("-1")) { type = bbdd_or; } else if (cover.first[0] == kitty::cube("10") && cover.first[1] == kitty::cube("01")) { type = bbdd_xor; } else if (cover.first[0] == kitty::cube("11") && cover.first[1] == kitty::cube("00")) { type = bbdd_xnor; } } else if (cover.first.size() == 3) { if (cover.first[0] == kitty::cube("10") && cover.first[1] == kitty::cube("01") && cover.first[0] == kitty::cube("11")) { type = bbdd_or; } } - } else if (!cover.second) { // off-set + } else if (!cover.second) { + // off-set if (cover.first.size() == 1) { if (cover.first[0] == kitty::cube("")) { type = bbdd_zero; } if (cover.first[0] == kitty::cube("00")) { type = bbdd_or; } else if (cover.first[0] == kitty::cube("01")) { type = bbdd_ornot; } else if (cover.first[0] == kitty::cube("10")) { type = bbdd_notor; } else if (cover.first[0] == kitty::cube("11")) { type = bbdd_nor; } } } if (type == bbdd_none) { kitty::print_cubes(cover.first); } assert(type != bbdd_none && "[ERROR] cube function not implemented\n"); return type; } - // format list(progress name, (share, base)) - void static show_progress_bar(std::vector>> progress_v, - int bar_width) { + /** + * @brief displays progress bar based on given input. Is used to display + * progress of converting cover graph to optimization data structure + * + * @param progress_v needs the format (name, (share, base)) + * @param bar_width total width in caracters for the progress bar + */ + static void show_progress_bar( + std::vector>> progress_v, + int bar_width) { for (std::pair> progress : progress_v) { std::string name = progress.first; int share = progress.second.first; int base = progress.second.second; int current_width = bar_width / progress_v.size(); - float percent = (float)share / base; + float percent = static_cast(share) / base; int pos = percent * current_width; std::cout << name << ": ["; for (int i = 0; i < current_width; i++) { if (i < pos) std::cout << "="; else if (i == pos) std::cout << ">"; else std::cout << " "; } - std::cout << "] " << share << "/" << base << " " << (int)(percent * 100) << "% "; + std::cout << "] " << share << "/" << base << " " + << static_cast(percent * 100) << "% "; } std::cout << " \r"; std::cout.flush(); } }; diff --git a/src/convert_bbdd.cpp b/src/convert_bbdd.cpp index 39d1501..60c0876 100644 --- a/src/convert_bbdd.cpp +++ b/src/convert_bbdd.cpp @@ -1,163 +1,166 @@ +// Copyright 2025 Oliver Theimer #include #include #include #include -#include +#include +#include +#include "bbdd/include/bbdd.hpp" +#include "bbdd/include/unique_table.hpp" +#include "util/cover_to_bbdd.hpp" #include #include #include #include -#include "bbdd/include/bbdd.hpp" -#include "bbdd/include/unique_table.hpp" -#include "util/cover_to_bbdd.hpp" - int main(int argc, char *argv[]) { bool vis = false; bool use_height = false; bool use_order_input = false; std::string order_output_dir; int sifting_repetitions = 1; int table_size = 20000000; int opt; while ((opt = getopt(argc, argv, "i:vhr:t:")) != -1) { switch (opt) { case 'i': use_order_input = true; order_output_dir = optarg; break; case 'v': vis = true; break; case 'h': use_height = true; break; case 't': { char *endptr = nullptr; table_size = std::strtol(optarg, &endptr, 10); if (*endptr != '\0') { - std::cerr << "[ERROR] Invalid integer for option -t: " << optarg << std::endl; + std::cerr << "[ERROR] Invalid integer for option -t: " << optarg + << std::endl; return EXIT_FAILURE; } - if (table_size < 0 || table_size > pow(2, 31)){ + if (table_size < 0 || table_size > pow(2, 31)) { std::cerr << "[ERROR] Invalid integer: " << optarg << std::endl; return EXIT_FAILURE; } break; } case 'r': { char *endptr = nullptr; sifting_repetitions = std::strtol(optarg, &endptr, 10); if (*endptr != '\0') { - std::cerr << "[ERROR] Invalid integer for option -r: " << optarg << std::endl; + std::cerr << "[ERROR] Invalid integer for option -r: " << optarg + << std::endl; return EXIT_FAILURE; } break; } default: std::cerr << "Usage: " << argv[0] << " [-v] [-r ordering_output_file] " << std::endl; return EXIT_FAILURE; } } if (optind >= argc) { std::cout << "[ERROR] input file in blif format is missing\n"; std::cerr << "[INFO] Usage: " << argv[0] << " [-v] " << std::endl; return EXIT_FAILURE; } std::string benchmark(argv[optind]); if (!std::filesystem::exists(benchmark)) { std::cout << "[ERROR] File does not exist\n"; return EXIT_FAILURE; } std::filesystem::path path(benchmark); std::string base_name = path.stem().string(); mockturtle::cover_network cover; if (lorina::read_blif(benchmark, mockturtle::blif_reader(cover)) != lorina::return_code::success) { std::cout << "[ERROR] While Lorina tried to read in file\n"; return EXIT_FAILURE; } std::vector cvo_input_v; if (use_order_input) { std::string line; std::cout << "Enter variable ordering separated by spaces (leave empty for " "default ordering): "; std::getline(std::cin, line); std::stringstream str_s(line); int num; while (str_s >> num) { cvo_input_v.push_back(num); } if (cover._storage->inputs.size() != cvo_input_v.size() && !cvo_input_v.empty()) { std::cerr << "[ERROR] Number of variables in ordering does not match " "number of inputs\n"; return EXIT_FAILURE; } } use_order_input = true; cvo_input_v = {}; printf("[INFO] cover with %zu nodes\n", cover._storage->nodes.size()); Unique_table table; table.init_table(table_size, cover.get_module_name()); if (use_order_input && !cvo_input_v.empty()) { table.init_cvo(cover._storage->inputs, cvo_input, cvo_input_v); } else { table.init_cvo(cover._storage->inputs, cvo_none); } std::filesystem::path order_output_dir_path; std::filesystem::path base_name_path; std::filesystem::path order_file_path; std::ofstream order_file; if (use_order_input) { order_output_dir_path = order_output_dir; base_name_path = base_name; base_name_path.replace_extension(".csv"); order_file_path = order_output_dir_path / base_name_path; bool order_file_exitsts = std::filesystem::exists(order_file_path); order_file.open(order_file_path, std::ios::app); if (!order_file_exitsts) { order_file << "order_in;order_pos;height;nodes\n"; } } - cover_to_bbdd(&table, cover, use_height, sifting_repetitions, order_file); + cover_to_bbdd(&table, cover, use_height, sifting_repetitions); std::cout << "[INFO] BBDD created\n"; if (vis) { std::cout << "[INFO] dumping result into .dot file\n"; table.dump_table(); table.dump_dot("temp/" + base_name + ".dot", cover.signal_map); system( ("dot -Tpng temp/" + base_name + ".dot -o temp/" + base_name + ".png") .c_str()); } #ifdef CACHE_STATS table.print_cache_stats(); table.dump_cache_stats("temp/" + base_name + "_cache_stats.csv"); #endif if (use_order_input) { std::cout << "[INFO] Writing ordering, total height, total number of nodes to " << order_file_path << "\n"; dump_ordering(table.cvo, order_file); order_file << ";" << table.get_total_height() << ";" << table.get_total_number_nodes() << "\n"; order_file.close(); } std::cout << "[INFO] Writing bbdd into blif file\n"; - table.write_blif("temp/" + base_name + "_bbdd" + - (use_height ? "_height" : "") + ".blif", - cover.get_module_name(), cover.signal_map, cover._storage->inputs.size()); + table.write_blif( + "temp/" + base_name + "_bbdd" + (use_height ? "_height" : "") + ".blif", + cover.get_module_name(), cover.signal_map, cover._storage->inputs.size()); table.free_table(); return EXIT_SUCCESS; } diff --git a/src/convert_bdd.cpp b/src/convert_bdd.cpp index 9f1c308..7af27e2 100644 --- a/src/convert_bdd.cpp +++ b/src/convert_bdd.cpp @@ -1,148 +1,149 @@ +// Copyright 2025 Oliver Theimer #include #include #include #include #include -#include +#include +#include #include #include #include #include -#include "util/cover_to_bdd.hpp" #include "bdd.h" #include "mockturtle/io/write_blif.hpp" #include "mockturtle/networks/cover.hpp" +#include "util/cover_to_bdd.hpp" int write_blif_recursive(std::ofstream &blif_file, cover_network cover, const BDD &node, int next_index, bool output) { if (node < 2) { return node; } int low_out = write_blif_recursive(blif_file, cover, bdd_low(node), next_index, false); int high_out = write_blif_recursive(blif_file, cover, bdd_high(node), next_index++, false); blif_file << ".names " << cover.signal_map[bdd_var(node)] << " "; if (IS_TERM(low_out)) { if (low_out == 0) { blif_file << "$false "; } else { blif_file << "$true "; } } else { blif_file << std::to_string(low_out); } blif_file << " "; if (IS_TERM(high_out)) { if (high_out == 0) { blif_file << "$false "; } else { blif_file << "$true "; } } else { blif_file << std::to_string(high_out) << " "; } /*blif_file << std::format( ".names {} {} {} {}", cover.signal_map[bdd_var(node)], IS_TERM(low_out) ? (low_out == 0 ? "$false" : "$true") : std::to_string(low_out), IS_TERM(high_out) ? (high_out == 0 ? "$false" : "$true") : std::to_string(high_out), !output ? std::to_string(node) : "");*/ if (!output) { blif_file << std::to_string(node); blif_file << "\n0-1 1\n11- 1\n"; } return node; } void write_blif(std::string filename, mockturtle::cover_network cover, std::vector> output_map) { std::ofstream blif_file(filename); blif_file << ".model " + cover.get_module_name() + "\n"; blif_file << ".inputs"; for (unsigned int i = 0; i < cover.signal_map.size(); i++) { blif_file << " " << cover.signal_map[i]; if (i + 1 == cover._storage->inputs.size()) { blif_file << "\n.outputs"; } } blif_file << "\n.names $true\n1\n"; blif_file << ".names $false\n"; int next_index = cover._storage->inputs.size() + 1; for (std::pair out_map : output_map) { if (out_map.first == bdd_true()) { blif_file << ".names " << out_map.second << "\n1\n"; } else if (out_map.first == bdd_false()) { blif_file << ".names " << out_map.second << "\n0\n"; } else { write_blif_recursive(blif_file, cover, out_map.first.id(), next_index, true); blif_file << out_map.second << "\n0-1 1\n11- 1\n"; } } blif_file << ".end\n"; } int get_bdd_height(BDD node) { if (node < 2) { return 0; } int low_height = get_bdd_height(bdd_low(node)); int high_height = get_bdd_height(bdd_high(node)); return std::max(low_height, high_height) + 1; } int get_total_height(std::vector> output_map) { int max_height = -1; for (std::pair out_map : output_map) { int current_height = get_bdd_height(out_map.first.id()); if (current_height > max_height) { max_height = current_height; } } return max_height; } int main(int argc, char *argv[]) { if (optind >= argc) { std::cout << "[ERROR] input file in blif format is missing\n"; - std::cerr << "[INFO] Usage: " << argv[0] << " " - << std::endl; + std::cerr << "[INFO] Usage: " << argv[0] << " " << std::endl; return EXIT_FAILURE; } std::string benchmark(argv[optind]); if (!std::filesystem::exists(benchmark)) { std::cout << "[ERROR] File does not exist\n"; return EXIT_FAILURE; } std::filesystem::path path(benchmark); std::string base_name = path.stem().string(); mockturtle::cover_network cover; // lorina::diagnostic_engine diag; if (lorina::read_blif(benchmark, mockturtle::blif_reader(cover)) != lorina::return_code::success) { std::cout << "[ERROR] While Lorina tried to read in file\n"; return EXIT_FAILURE; } std::vector> output_map; bdd_init(300000, 10000); bdd_setvarnum(cover._storage->inputs.size()); bdd_autoreorder(BDD_REORDER_SIFT); printf("[INFO] init with %zu variables\n", cover._storage->inputs.size()); cover_to_bdd(cover, output_map); - // printf("height before: %d\n", get_total_height(output_map)); - bdd_reorder(BDD_REORDER_SIFT); //bdd_reorder_siftite is the same but repeats until no more progress is done + // bdd_reorder_siftite is the same but repeats until no more progress is done + bdd_reorder(BDD_REORDER_SIFT); printf("height after: %d\n", get_total_height(output_map)); write_blif("temp/" + base_name + "_bdd.blif", cover, output_map); bdd_done(); return EXIT_SUCCESS; } diff --git a/src/convert_muxig.cpp b/src/convert_muxig.cpp index 5c30f41..971e789 100644 --- a/src/convert_muxig.cpp +++ b/src/convert_muxig.cpp @@ -1,94 +1,94 @@ +// Copyright 2025 Oliver Theimer #include #include +#include + +#include "lorina/blif.hpp" #include #include #include #include #include -#include - -#include "lorina/blif.hpp" #include "mockturtle/algorithms/cover_to_graph.hpp" #include "mockturtle/networks/cover.hpp" #include "mockturtle/networks/muxig.hpp" - #include "mockturtle/algorithms/sim_resub.hpp" #include "mockturtle/io/blif_reader.hpp" #include "mockturtle/io/write_blif.hpp" int main(int argc, char *argv[]) { // Default values - int max_pis = 10; // 8; + int max_pis = 10; int max_divisors = 150; - int max_inserts = 20; // 2; + int max_inserts = 20; int opt; while ((opt = getopt(argc, argv, "o:p:d:i:")) != -1) { switch (opt) { case 'p': max_pis = std::atoi(optarg); break; case 'o': break; case 'd': max_divisors = std::atoi(optarg); break; case 'i': max_inserts = std::atoi(optarg); break; default: std::cerr << "Usage: " << argv[0] << " [-p max_pi] [-d max_divisors] [-i max_inserts] " "\n"; return 1; } } std::string benchmark; if (optind < argc) { benchmark = argv[optind]; } else { std::cerr << "Error: Missing required positional argument.\n"; std::cerr << "Usage: " << argv[0] << " [-p max_pi] [-d max_divisors] [-i max_inserts] \n"; return 1; } if (!std::filesystem::exists(benchmark)) { std::cout << "[ERROR] File does not exist\n"; return EXIT_FAILURE; } std::filesystem::path path(benchmark); std::string base_name = path.stem().string(); mockturtle::cover_network cover; if (lorina::read_blif(benchmark, mockturtle::blif_reader(cover)) != lorina::return_code::success) { std::cout << "[ERROR] While Lorina tried to read in file\n"; return EXIT_FAILURE; } mockturtle::muxig_network muxig_original = mockturtle::convert_cover_to_graph(cover); mockturtle::resubstitution_params ps; mockturtle::resubstitution_stats st; ps.max_inserts = max_inserts; ps.max_pis = max_pis; ps.max_divisors = max_divisors; ps.progress = false; ps.verbose = false; mockturtle::sim_resubstitution(muxig_original, ps, &st); muxig_original = mockturtle::cleanup_dangling(muxig_original); mockturtle::write_blif(muxig_original, "temp/" + base_name + "_muxig_temp.blif"); return EXIT_SUCCESS; }