From 422e7ef8606dd6e82be0bbe76ab6b1fbeff15e50 Mon Sep 17 00:00:00 2001 From: SJulianS Date: Mon, 6 May 2024 17:33:24 +0200 Subject: [PATCH] start to restructure graph_algorithm plugin (disfunctional) --- plugins/graph_algorithm/CMakeLists.txt | 2 +- .../graph_algorithm/algorithms/components.h | 42 +++ .../include/graph_algorithm/netlist_graph.h | 81 ++++++ .../graph_algorithm/plugin_graph_algorithm.h | 79 ------ .../python/python_bindings.cpp | 109 ++++---- .../src/algorithms/components.cpp | 68 +++++ .../clustering/communities_fast_greedy.cpp | 50 ---- .../src/clustering/communities_multilevel.cpp | 58 ---- .../src/clustering/communities_spinglass.cpp | 68 ----- .../src/clustering/community_detection.cpp | 118 -------- .../graph_algorithm/src/graph/graph_cut.cpp | 58 ---- .../graph/strongly_connected_components.cpp | 53 ---- plugins/graph_algorithm/src/igraph.cpp | 148 ---------- plugins/graph_algorithm/src/netlist_graph.cpp | 252 ++++++++++++++++++ 14 files changed, 499 insertions(+), 687 deletions(-) create mode 100644 plugins/graph_algorithm/include/graph_algorithm/algorithms/components.h create mode 100644 plugins/graph_algorithm/include/graph_algorithm/netlist_graph.h create mode 100644 plugins/graph_algorithm/src/algorithms/components.cpp delete mode 100644 plugins/graph_algorithm/src/clustering/communities_fast_greedy.cpp delete mode 100644 plugins/graph_algorithm/src/clustering/communities_multilevel.cpp delete mode 100644 plugins/graph_algorithm/src/clustering/communities_spinglass.cpp delete mode 100644 plugins/graph_algorithm/src/clustering/community_detection.cpp delete mode 100644 plugins/graph_algorithm/src/graph/graph_cut.cpp delete mode 100644 plugins/graph_algorithm/src/graph/strongly_connected_components.cpp delete mode 100644 plugins/graph_algorithm/src/igraph.cpp create mode 100644 plugins/graph_algorithm/src/netlist_graph.cpp diff --git a/plugins/graph_algorithm/CMakeLists.txt b/plugins/graph_algorithm/CMakeLists.txt index fa2e5089017..d4f936101ed 100644 --- a/plugins/graph_algorithm/CMakeLists.txt +++ b/plugins/graph_algorithm/CMakeLists.txt @@ -1,4 +1,4 @@ -option(PL_GRAPH_ALGORITHM "PL_GRAPH_ALGORITHM" OFF) +option(PL_GRAPH_ALGORITHM "PL_GRAPH_ALGORITHM" ON) if(PL_GRAPH_ALGORITHM OR BUILD_ALL_PLUGINS) file(GLOB_RECURSE GRAPH_ALGORITHM_INC ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h) diff --git a/plugins/graph_algorithm/include/graph_algorithm/algorithms/components.h b/plugins/graph_algorithm/include/graph_algorithm/algorithms/components.h new file mode 100644 index 00000000000..e6daf43f213 --- /dev/null +++ b/plugins/graph_algorithm/include/graph_algorithm/algorithms/components.h @@ -0,0 +1,42 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "hal_core/defines.h" +#include "hal_core/utilities/result.h" + +#include +#include + +namespace hal +{ + namespace graph_algorithm + { + class NetlistGraph; + + Result>> get_connected_components(const NetlistGraph* graph, bool strong); + } // namespace graph_algorithm +} // namespace hal \ No newline at end of file diff --git a/plugins/graph_algorithm/include/graph_algorithm/netlist_graph.h b/plugins/graph_algorithm/include/graph_algorithm/netlist_graph.h new file mode 100644 index 00000000000..a4deeade9ac --- /dev/null +++ b/plugins/graph_algorithm/include/graph_algorithm/netlist_graph.h @@ -0,0 +1,81 @@ +// MIT License +// +// Copyright (c) 2019 Ruhr University Bochum, Chair for Embedded Security. All Rights reserved. +// Copyright (c) 2019 Marc Fyrbiak, Sebastian Wallat, Max Hoffmann ("ORIGINAL AUTHORS"). All rights reserved. +// Copyright (c) 2021 Max Planck Institute for Security and Privacy. All Rights reserved. +// Copyright (c) 2021 Jörn Langheinrich, Julian Speith, Nils Albartus, René Walendy, Simon Klix ("ORIGINAL AUTHORS"). All Rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#pragma once + +#include "hal_core/defines.h" +#include "hal_core/utilities/result.h" + +#include +#include +#include +#include + +namespace hal +{ + class Netlist; + class Gate; + class Net; + + namespace graph_algorithm + { + class NetlistGraph + { + public: + ~NetlistGraph(); + + static Result> from_netlist(Netlist* nl, bool create_dummy_nodes = false, const std::function& filter = nullptr); + + // TODO implement + static Result> from_netlist_no_edges(Netlist* nl); + + Netlist* get_netlist() const; + igraph_t* get_graph() const; + + Result get_gate_of_vertex(const u32 node) const; + Result> get_gates_of_vertices(const std::set& nodes) const; + Result> get_gates_of_vertices(const std::vector& nodes) const; + + Result get_vertex_of_gate(Gate* g) const; + + // TODO implement 4 below + void add_edges(const std::vector>& edges); + void add_edges(const std::vector>& edges); + void add_edges(const std::vector& edges); + void delete_edges(const std::vector>& edges); + void delete_edges(const std::vector>& edges); + void delete_edges(const std::vector& edges); + + private: + NetlistGraph() = delete; + NetlistGraph(Netlist* nl); + + Netlist* m_nl; + igraph_t* m_graph; + std::unordered_map m_nodes_to_gates; + std::unordered_map m_gates_to_nodes; + }; + } // namespace graph_algorithm +} // namespace hal \ No newline at end of file diff --git a/plugins/graph_algorithm/include/graph_algorithm/plugin_graph_algorithm.h b/plugins/graph_algorithm/include/graph_algorithm/plugin_graph_algorithm.h index 057894ffda3..a5c3c399d5e 100644 --- a/plugins/graph_algorithm/include/graph_algorithm/plugin_graph_algorithm.h +++ b/plugins/graph_algorithm/include/graph_algorithm/plugin_graph_algorithm.h @@ -62,84 +62,5 @@ namespace hal * @returns The version of the plugin. */ std::string get_version() const override; - - /* - * clustering function - */ - - /** - * Get a map of community IDs to communities. Each community is represented by a set of gates. - * - * @param[in] netlist - The netlist to operate on. - * @returns A map from community IDs to communities. - */ - std::map> get_communities(Netlist* const netlist); - - /** - * Get a map of community IDs to communities running the spinglass clustering algorithm. Each community is represented by a set of gates. - * - * @param[in] netlist - The netlist to operate on. - * @param[in] spins - The number of spins. - * @returns A map from community IDs to communities. - */ - std::map> get_communities_spinglass(Netlist* const netlist, u32 const spins); - - /** - * Get a map of community IDs to communities running the fast greedy clustering algorithm from igraph. Each community is represented by a set of gates. - * - * @param[in] netlist - The netlist to operate on. - * @returns A map from community IDs to communities. - */ - std::map> get_communities_fast_greedy(Netlist* const netlist); - - /** - * Get a vector of strongly connected components (SCC) with each SSC being represented by a vector of gates. - * - * @param[in] netlist - The netlist to operate on. - * @returns A vector of SCCs. - */ - std::vector> get_strongly_connected_components(Netlist* netlist); - - /** - * Get a graph cut for a specific gate and depth. Further, a set of gates can be specified that limit the graph cut, i.e., flip-flops and memory cells.
- * The graph cut is returned as a vector of sets of gates with the vector's index representing the distance of each set to the starting point. - * - * @param[in] netlist - The netlist to operate on. - * @param[in] gate - The gate that is the starting point for the graph cut. - * @param[in] depth - The depth of the graph cut. - * @param[in] terminal_gate_type - A set of gates at which to terminate the graph cut. - * @returns The graph cut as a vector of sets of gates. - */ - std::vector> - get_graph_cut(Netlist* const netlist, Gate* gate, const u32 depth = std::numeric_limits::max(), const std::set terminal_gate_type = std::set()); - - /* - * igraph specific functions - */ - - /** - * Generates an directed graph based on the current netlist. Each gate is transformed to a node while each - * net is transformed to an edge. The function returns the mapping from igraph node ids to HAL gates. Note - * that for each global input and output dummy nodes are generated in the igraph representation. - * - * @param[in] netlist - The netlist to operate on. - * @param[in] igraph - igraph object - * @returns map from igraph node id to HAL gate ID, to be able to match back any graph operations. - */ - std::map get_igraph_directed(Netlist* const netlist, igraph_t* igraph); - - /** - * Uses the mapping provided by the the get_igraph_directed() function to generate sets of HAL gates - * that were generated by the clustering algorithms of igraph. The igraph membership vector contains - * the generated clusters from the igraph framework, which is used to generate the sets of gates in HAL. - * The sets are stored in a map with the regarding cluster ID from igraph, since these can contain information - * generated by the clustering algorithm. - * - * @param[in] graph - igraph graph object - * @param[in] membership - membership vector - * @param[in] vertex_to_gate - map from node ID in igraph to HAL gate - * @returns map from membership id to set of gates that have the membership. - */ - std::map> get_memberships_for_hal(igraph_t* graph, igraph_vector_int_t *membership, std::map vertex_to_gate); }; } // namespace hal diff --git a/plugins/graph_algorithm/python/python_bindings.cpp b/plugins/graph_algorithm/python/python_bindings.cpp index 13ad9dc852e..2547a1863a6 100644 --- a/plugins/graph_algorithm/python/python_bindings.cpp +++ b/plugins/graph_algorithm/python/python_bindings.cpp @@ -60,60 +60,61 @@ namespace hal :returns: Plugin version. :rtype: str )") - .def("get_communities", &GraphAlgorithmPlugin::get_communities, py::arg("netlist"), R"( - Get a dict of community IDs to communities. Each community is represented by a set of gates. - - :param hal_py.Netlist netlist: The netlist to operate on. - :returns: A dict from community IDs to communities. - :rtype: dict[int,set[hal_py.get_gate()]] - )") - .def("get_communities_spinglass", &GraphAlgorithmPlugin::get_communities_spinglass, py::arg("netlist"), py::arg("spins"), R"( - Get a dict of community IDs to communities running the spinglass clustering algorithm. Each community is represented by a set of gates. - - :param hal_py.Netlist netlist: The netlist to operate on. - :param int spins: The number of spins. - :returns: A dict from community IDs to communities. - :rtype: dict[int,set[hal_py.get_gate()]] - )") - .def("get_communities_fast_greedy", &GraphAlgorithmPlugin::get_communities_fast_greedy, py::arg("netlist"), R"( - Get a dict of community IDs to communities running the fast greedy clustering algorithm from igraph. Each community is represented by a set of gates. - - :param hal_py.Netlist netlist: The netlist to operate on. - :returns: A dict from community IDs to communities. - :rtype: dict[set[hal_py.get_gate()]] - )") - /* - .def("get_communities_multilevel", &GraphAlgorithmPlugin::get_communities_multilevel, py::arg("netlist"), R"( - Get a dict of community IDs to communities running the multilevel clustering algorithm from igraph. Each community is represented by a set of gates. - - :param hal_py.Netlist netlist: The netlist to operate on. - :returns: A dict from community IDs to communities. - :rtype: dict[int,set[hal_py.get_gate()]] - )") */ - .def("get_strongly_connected_components", &GraphAlgorithmPlugin::get_strongly_connected_components, py::arg("netlist"), R"( - Get a list of strongly connected components (SCC) with each SSC being represented by a list of gates. - - :param hal_py.Netlist netlist: The netlist to operate on. - :returns: A list of SCCs. - :rtype: list[list[hal_py.get_gate()]] - )") - .def("get_graph_cut", - &GraphAlgorithmPlugin::get_graph_cut, - py::arg("netlist"), - py::arg("gate"), - py::arg("depth") = std::numeric_limits::max(), - py::arg("terminal_gate_type") = std::set(), - R"( - Get a graph cut for a specific gate and depth. Further, a set of gates can be specified that limit the graph cut, i.e., flip-flops and memory cells. - The graph cut is returned as a list of sets of gates with the list's index representing the distance of each set to the starting point. - - :param hal_py.Netlist netlist: The netlist to operate on. - :param hal_py.get_gate() gate: The gate that is the starting point for the graph cut. - :param int depth: The depth of the graph cut. - :param set[str] terminal_gate_type: A set of gates at which to terminate the graph cut. - :returns: The graph cut as a list of sets of gates. - :rtype: list[set[hal_py.get_gate()]] - )"); + // .def("get_communities", &GraphAlgorithmPlugin::get_communities, py::arg("netlist"), R"( + // Get a dict of community IDs to communities. Each community is represented by a set of gates. + + // :param hal_py.Netlist netlist: The netlist to operate on. + // :returns: A dict from community IDs to communities. + // :rtype: dict[int,set[hal_py.get_gate()]] + // )") + // .def("get_communities_spinglass", &GraphAlgorithmPlugin::get_communities_spinglass, py::arg("netlist"), py::arg("spins"), R"( + // Get a dict of community IDs to communities running the spinglass clustering algorithm. Each community is represented by a set of gates. + + // :param hal_py.Netlist netlist: The netlist to operate on. + // :param int spins: The number of spins. + // :returns: A dict from community IDs to communities. + // :rtype: dict[int,set[hal_py.get_gate()]] + // )") + // .def("get_communities_fast_greedy", &GraphAlgorithmPlugin::get_communities_fast_greedy, py::arg("netlist"), R"( + // Get a dict of community IDs to communities running the fast greedy clustering algorithm from igraph. Each community is represented by a set of gates. + + // :param hal_py.Netlist netlist: The netlist to operate on. + // :returns: A dict from community IDs to communities. + // :rtype: dict[set[hal_py.get_gate()]] + // )") + // /* + // .def("get_communities_multilevel", &GraphAlgorithmPlugin::get_communities_multilevel, py::arg("netlist"), R"( + // Get a dict of community IDs to communities running the multilevel clustering algorithm from igraph. Each community is represented by a set of gates. + + // :param hal_py.Netlist netlist: The netlist to operate on. + // :returns: A dict from community IDs to communities. + // :rtype: dict[int,set[hal_py.get_gate()]] + // )") */ + // .def("get_strongly_connected_components", &GraphAlgorithmPlugin::get_strongly_connected_components, py::arg("netlist"), R"( + // Get a list of strongly connected components (SCC) with each SSC being represented by a list of gates. + + // :param hal_py.Netlist netlist: The netlist to operate on. + // :returns: A list of SCCs. + // :rtype: list[list[hal_py.get_gate()]] + // )") + // .def("get_graph_cut", + // &GraphAlgorithmPlugin::get_graph_cut, + // py::arg("netlist"), + // py::arg("gate"), + // py::arg("depth") = std::numeric_limits::max(), + // py::arg("terminal_gate_type") = std::set(), + // R"( + // Get a graph cut for a specific gate and depth. Further, a set of gates can be specified that limit the graph cut, i.e., flip-flops and memory cells. + // The graph cut is returned as a list of sets of gates with the list's index representing the distance of each set to the starting point. + + // :param hal_py.Netlist netlist: The netlist to operate on. + // :param hal_py.get_gate() gate: The gate that is the starting point for the graph cut. + // :param int depth: The depth of the graph cut. + // :param set[str] terminal_gate_type: A set of gates at which to terminate the graph cut. + // :returns: The graph cut as a list of sets of gates. + // :rtype: list[set[hal_py.get_gate()]] + // )") + ; #ifndef PYBIND11_MODULE return m.ptr(); diff --git a/plugins/graph_algorithm/src/algorithms/components.cpp b/plugins/graph_algorithm/src/algorithms/components.cpp new file mode 100644 index 00000000000..1145683a9c1 --- /dev/null +++ b/plugins/graph_algorithm/src/algorithms/components.cpp @@ -0,0 +1,68 @@ +#include "graph_algorithm/algorithms/components.h" + +#include "graph_algorithm/netlist_graph.h" + +#include + +namespace hal +{ + namespace graph_algorithm + { + Result>> get_connected_components(const NetlistGraph* graph, bool strong) + { + if (graph == nullptr) + { + return ERR("graph is a nullptr"); + } + + igraph_vector_int_t membership, csize; + igraph_integer_t number_of_clusters; + auto err = igraph_vector_int_init(&membership, 0); + if (err != IGRAPH_SUCCESS) + { + igraph_vector_int_destroy(&membership); + return ERR(igraph_strerror(err)); + } + + err = igraph_vector_int_init(&csize, 0); + if (err != IGRAPH_SUCCESS) + { + igraph_vector_int_destroy(&membership); + igraph_vector_int_destroy(&csize); + return ERR(igraph_strerror(err)); + } + + igraph_t* igr = graph->get_graph(); + + // run scc + err = igraph_clusters(igr, &membership, &csize, &number_of_clusters, strong ? IGRAPH_STRONG : IGRAPH_WEAK); + if (err != IGRAPH_SUCCESS) + { + igraph_vector_int_destroy(&membership); + igraph_vector_int_destroy(&csize); + return ERR(igraph_strerror(err)); + } + + // map back to HAL structures + u32 num_vertices = (u32)igraph_vcount(igr); + std::map> components; + + for (i32 i = 0; i < num_vertices; i++) + { + components[VECTOR(membership)[i]].insert(i); + } + + // convert to set + std::set> sccs; + for (auto& [_, members] : components) + { + sccs.insert(std::move(members)); + } + + igraph_vector_int_destroy(&membership); + igraph_vector_int_destroy(&csize); + + return OK(sccs); + } + } // namespace graph_algorithm +} // namespace hal \ No newline at end of file diff --git a/plugins/graph_algorithm/src/clustering/communities_fast_greedy.cpp b/plugins/graph_algorithm/src/clustering/communities_fast_greedy.cpp deleted file mode 100644 index 0aa441064bb..00000000000 --- a/plugins/graph_algorithm/src/clustering/communities_fast_greedy.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "graph_algorithm/plugin_graph_algorithm.h" -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/net.h" -#include "hal_core/netlist/netlist.h" -#include "hal_core/plugin_system/plugin_manager.h" -#include "hal_core/utilities/log.h" - -#include -#include - -namespace hal -{ - std::map> GraphAlgorithmPlugin::get_communities_fast_greedy(Netlist* nl) - { - if (nl == nullptr) - { - log_error(this->get_name(), "{}", "parameter 'nl' is nullptr"); - return std::map>(); - } - // get igraph - igraph_t graph; - std::map vertex_to_gate = get_igraph_directed(nl, &graph); - - igraph_vector_int_t membership, modularity; - igraph_matrix_t merges; - - igraph_to_undirected(&graph, IGRAPH_TO_UNDIRECTED_MUTUAL, 0); - - igraph_vector_int_init(&membership, 1); - - igraph_community_fastgreedy(&graph, - nullptr, /* no weights */ - nullptr, - nullptr, - &membership); - - // map back to HAL structures - std::map> community_sets; - for (igraph_integer_t i = 0; i < igraph_vector_int_size(&membership); i++) - { - community_sets[VECTOR(membership)[i]].insert(vertex_to_gate[i]); - } - //igraph_vector_destroy(&membership); - - igraph_destroy(&graph); - igraph_vector_int_destroy(&membership); - - return community_sets; - } -} // namespace hal diff --git a/plugins/graph_algorithm/src/clustering/communities_multilevel.cpp b/plugins/graph_algorithm/src/clustering/communities_multilevel.cpp deleted file mode 100644 index 51c84d0e768..00000000000 --- a/plugins/graph_algorithm/src/clustering/communities_multilevel.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* -#include "graph_algorithm/plugin_graph_algorithm.h" -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/net.h" -#include "hal_core/netlist/netlist.h" -#include "hal_core/plugin_system/plugin_manager.h" -#include "hal_core/utilities/log.h" - -#include -#include - -namespace hal -{ - std::map> GraphAlgorithmPlugin::get_communities_multilevel(Netlist* nl) - { - if (nl == nullptr) - { - log_error(this->get_name(), "{}", "parameter 'nl' is nullptr"); - return std::map>(); - } - - // get igraph - igraph_t graph; - std::map vertex_to_gate = get_igraph_directed(nl, &graph); - - // convert to undirected - igraph_to_undirected(&graph, IGRAPH_TO_UNDIRECTED_MUTUAL, 0); - - igraph_vector_t membership_vec, modularity; - igraph_matrix_t membership_mat; - - igraph_vector_init(&membership_vec, 1); - igraph_vector_init(&modularity, 1); - igraph_matrix_init(&membership_mat, 1, 1); - - igraph_community_multilevel(&graph, - 0, - 0, - &membership_vec, - &membership_mat, - &modularity); - - // map back to HAL structures - std::map> community_sets; - for (int i = 0; i < igraph_vector_size(&membership_vec); i++) - { - community_sets[(int)VECTOR(membership_vec)[i]].insert(vertex_to_gate[i]); - } - - igraph_destroy(&graph); - igraph_vector_destroy(&membership_vec); - igraph_vector_destroy(&modularity); - igraph_matrix_destroy(&membership_mat); - - return community_sets; - } -} // namespace hal -*/ \ No newline at end of file diff --git a/plugins/graph_algorithm/src/clustering/communities_spinglass.cpp b/plugins/graph_algorithm/src/clustering/communities_spinglass.cpp deleted file mode 100644 index 461f05190df..00000000000 --- a/plugins/graph_algorithm/src/clustering/communities_spinglass.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "graph_algorithm/plugin_graph_algorithm.h" -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/net.h" -#include "hal_core/netlist/netlist.h" -#include "hal_core/plugin_system/plugin_manager.h" -#include "hal_core/utilities/log.h" - -#include -#include - -namespace hal -{ - std::map> GraphAlgorithmPlugin::get_communities_spinglass(Netlist* const nl, u32 const spins) - { - if (nl == nullptr) - { - log_error(this->get_name(), "{}", "parameter 'nl' is nullptr"); - return std::map>(); - } - - log_info("graph_algorithm", "netlist has {} gates and {} nets", nl->get_gates().size(), nl->get_nets().size()); - - // get igraph - igraph_t graph; - std::map vertex_to_gate = get_igraph_directed(nl, &graph); - - - igraph_real_t modularity, temperature; - igraph_vector_int_t membership, csize; - - igraph_vector_int_init(&membership, 0); - igraph_vector_int_init(&csize, 0); - igraph_community_spinglass(&graph, - nullptr, /* no weights */ - &modularity, - &temperature, - &membership, - &csize, - spins, /* no of spins */ - false, /* parallel update */ - 1.0, /* start temperature */ - 0.01, /* stop temperature */ - 0.99, /* cooling factor */ - IGRAPH_SPINCOMM_UPDATE_CONFIG, - 1.0, /* gamma */ - IGRAPH_SPINCOMM_IMP_ORIG, - /*gamma-=*/0); - - log("Clustering successful:"); - log("\tModularity: {}", modularity); - - log("\tTemperature: {}", temperature); - log("\tCluster sizes: "); - for (igraph_integer_t i = 0; i < igraph_vector_int_size(&csize); i++) - { - log("\t\t{}", (long int)VECTOR(csize)[i]); - } - - // map back to HAL structures - auto community_sets = get_memberships_for_hal(&graph, &membership, vertex_to_gate); - - igraph_destroy(&graph); - igraph_vector_int_destroy(&membership); - igraph_vector_int_destroy(&csize); - - return community_sets; - } -} // namespace hal diff --git a/plugins/graph_algorithm/src/clustering/community_detection.cpp b/plugins/graph_algorithm/src/clustering/community_detection.cpp deleted file mode 100644 index b0b447de3ab..00000000000 --- a/plugins/graph_algorithm/src/clustering/community_detection.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#include "graph_algorithm/plugin_graph_algorithm.h" -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/net.h" -#include "hal_core/netlist/netlist.h" -#include "hal_core/utilities/log.h" - -#include - -namespace hal -{ - std::map> GraphAlgorithmPlugin::get_communities(Netlist* nl) - { - if (nl == nullptr) - { - log_error(this->get_name(), "{}", "parameter 'g' is nullptr"); - return std::map>(); - } - - /* delete leaves */ - bool deleted_leave; - do - { - deleted_leave = false; - for (const auto& test_gate : nl->get_gates()) - { - u32 counter = test_gate->get_predecessors().size() + test_gate->get_successors().size(); - if (counter < 2) - { - nl->delete_gate(test_gate); - deleted_leave = true; - } - /* delete leaves connected to a single gate as successor and predecessor */ - else if ((counter == 2) && (test_gate->get_predecessors().size() == 1) && (test_gate->get_successors().size() == 1)) - { - if (test_gate->get_predecessors()[0]->get_gate() == test_gate->get_successors()[0]->get_gate()) - { - nl->delete_gate(test_gate); - deleted_leave = true; - } - } - } - } while (deleted_leave); - - /* map netlist to igraph IDs for both directions */ - std::map nl_igraph_id_match, igraph_nl_id_match; - u32 id_count = 0; - for (const auto& single_gate : nl->get_gates()) - { - nl_igraph_id_match[single_gate->get_id()] = id_count; - igraph_nl_id_match[id_count] = single_gate->get_id(); - id_count++; - } - - /* count amount of nets, with all destinations of all nets */ - u32 edge_counter = 0; - for (auto net : nl->get_nets()) - { - assert(net->get_sources().size() == 1); - if (net->get_sources().front()->get_gate() == nullptr) - continue; - - for (const auto& successor : net->get_destinations()) - { - if (successor->get_gate() == nullptr) - continue; - edge_counter += 2; - } - } - - /* transform all nets to igraph_real_t */ - igraph_integer_t* edges = new igraph_integer_t[edge_counter]; - u32 edge_vertex_counter = 0; - for (auto net : nl->get_nets()) - { - assert(net->get_sources().size() == 1); - Gate* predecessor = net->get_sources().front()->get_gate(); - if (predecessor == nullptr) - continue; - u32 predecessor_id = nl_igraph_id_match[predecessor->get_id()]; - - for (const auto& successor : net->get_destinations()) - { - if (successor->get_gate() == nullptr) - continue; - auto successor_id = nl_igraph_id_match[successor->get_gate()->get_id()]; - edges[edge_vertex_counter++] = predecessor_id; - edges[edge_vertex_counter++] = successor_id; - } - } - - /* create and add edges to the graph */ - igraph_t graph; - igraph_vector_int_t netlist_edges; - igraph_vector_int_init_array(&netlist_edges, edges, edge_counter); - delete[] edges; - igraph_create(&graph, &netlist_edges, nl->get_gates().size(), IGRAPH_UNDIRECTED); - igraph_vector_int_destroy(&netlist_edges); - - /* remove double edges */ - igraph_simplify(&graph, true, false, 0); - - /* Louvain method without weights */ - igraph_vector_int_t membership; - igraph_vector_int_init(&membership, 0); - igraph_community_fastgreedy(&graph, nullptr, nullptr, nullptr, &membership); - igraph_destroy(&graph); - - /* group gates by community membership */ - std::map> community_sets; - for (igraph_integer_t i = 0; i < igraph_vector_int_size(&membership); i++) - { - community_sets[VECTOR(membership)[i]].insert(nl->get_gate_by_id(igraph_nl_id_match[i])); - } - igraph_vector_int_destroy(&membership); - - return community_sets; - } -} // namespace hal diff --git a/plugins/graph_algorithm/src/graph/graph_cut.cpp b/plugins/graph_algorithm/src/graph/graph_cut.cpp deleted file mode 100644 index 23dd475e58c..00000000000 --- a/plugins/graph_algorithm/src/graph/graph_cut.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include "graph_algorithm/plugin_graph_algorithm.h" -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/netlist.h" -#include "hal_core/utilities/log.h" - -namespace hal -{ - std::vector> GraphAlgorithmPlugin::get_graph_cut(Netlist* const g, Gate* current_gate, const u32 depth, const std::set terminal_gate_type) - { - if (g == nullptr) - { - log_error(this->get_name(), "parameter 'g' is nullptr."); - return std::vector>(); - } - if (current_gate == nullptr) - { - log_error(this->get_name(), "parameter 'gate' is nullptr."); - return std::vector>(); - } - if (depth == std::numeric_limits::max() && terminal_gate_type.empty()) - { - log_error(this->get_name(), "parameter 'depth' is 0 and no terminal gate type defined."); - return std::vector>(); - } - - std::vector> result; - result.push_back({current_gate}); - - if (depth == 1) - { - return result; - } - - for (u32 i = 1; i < depth; i++) - { - std::set previous_state = result.back(), next_state = std::set(); - for (const auto& it : previous_state) - { - for (const auto& predecessor : it->get_predecessors()) - { - if (terminal_gate_type.find(predecessor->get_gate()->get_type()->get_name()) == terminal_gate_type.end()) - { - next_state.insert(predecessor->get_gate()); - } - } - } - if (next_state.empty()) - { - return result; - } - else - { - result.push_back(next_state); - } - } - return result; - } -} // namespace hal diff --git a/plugins/graph_algorithm/src/graph/strongly_connected_components.cpp b/plugins/graph_algorithm/src/graph/strongly_connected_components.cpp deleted file mode 100644 index 9ba0ed0088f..00000000000 --- a/plugins/graph_algorithm/src/graph/strongly_connected_components.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "graph_algorithm/plugin_graph_algorithm.h" -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/net.h" -#include "hal_core/netlist/netlist.h" -#include "hal_core/plugin_system/plugin_manager.h" -#include "hal_core/utilities/log.h" - -#include -#include - -namespace hal -{ - std::vector> GraphAlgorithmPlugin::get_strongly_connected_components(Netlist* nl) - { - if (nl == nullptr) - { - log_error(this->get_name(), "{}", "parameter 'nl' is nullptr"); - return std::vector>(); - } - - // get igraph - igraph_t graph; - std::map vertex_to_gate = get_igraph_directed(nl, &graph); - - igraph_vector_int_t membership; - igraph_integer_t number_of_clusters; - igraph_vector_int_init(&membership, 0); - - // run scc - igraph_connected_components(&graph, &membership, nullptr, &number_of_clusters, IGRAPH_STRONG); - - // map back to HAL structures - std::map> ssc_membership = get_memberships_for_hal(&graph, &membership, vertex_to_gate); - - // convert to set - std::vector> sccs; - for (const auto& scc : ssc_membership) - { - std::vector scc_vector; - for (const auto& scc_gate : scc.second) - { - scc_vector.push_back(scc_gate); - } - sccs.push_back(scc_vector); - } - - // cleanup - igraph_destroy(&graph); - igraph_vector_int_destroy(&membership); - - return sccs; - } -} // namespace hal diff --git a/plugins/graph_algorithm/src/igraph.cpp b/plugins/graph_algorithm/src/igraph.cpp deleted file mode 100644 index 21ba4851db6..00000000000 --- a/plugins/graph_algorithm/src/igraph.cpp +++ /dev/null @@ -1,148 +0,0 @@ -#include "graph_algorithm/plugin_graph_algorithm.h" -#include "hal_core/netlist/gate.h" -#include "hal_core/netlist/net.h" -#include "hal_core/netlist/netlist.h" -#include "hal_core/plugin_system/plugin_manager.h" -#include "hal_core/utilities/log.h" - -#include -#include - -namespace hal -{ - std::map GraphAlgorithmPlugin::get_igraph_directed(Netlist* const nl, igraph_t* graph) - { - - // count all edges, remember in HAL one net(edge) has multiple sinks - u32 edge_counter = 0; - for (auto net : nl->get_nets()) - { - if (net->get_sources().size() > 1) - { - log_error("graph_algorithm", "multi-driven nets not yet supported! aborting"); - return std::map(); - } - - Gate* src_gate = nullptr; - - if (net->get_sources().size() != 0) - { - src_gate = net->get_sources().at(0)->get_gate(); - } - - std::vector dst_gates; - - auto dst_gates_endpoints = net->get_destinations(); - - for (const auto& dst_gate_endpoint : dst_gates_endpoints) - { - dst_gates.push_back(dst_gate_endpoint->get_gate()); - } - - // if gate has no src --> add exactly one dummy node - if (!src_gate) - { - edge_counter += dst_gates.size(); - } - // if gate has no dsts --> add dummy node - else if (dst_gates.size() == 0) - { - edge_counter++; - } - // default mode - else - { - edge_counter += dst_gates.size(); - } - } - - log_debug("graph_algorithm", "nets: {}, edge_counter: {}", nl->get_nets().size(), edge_counter); - - // initialize edge vector - igraph_vector_int_t edges; - igraph_vector_int_init(&edges, 2 * edge_counter); - - // we need dummy gates for input/outputs - u32 dummy_gate_counter = nl->get_gates().size() - 1; - u32 edge_vertex_counter = 0; - - for (auto net : nl->get_nets()) - { - Gate* src_gate = nullptr; - - if (net->get_sources().size() != 0) - { - src_gate = net->get_sources().at(0)->get_gate(); - } - - std::vector dst_gates; - - auto dst_gates_endpoints = net->get_destinations(); - - for (const auto& dst_gate_endpoint : dst_gates_endpoints) - { - dst_gates.push_back(dst_gate_endpoint->get_gate()); - } - - // if gate has no src --> add exactly one dummy node - if (src_gate == nullptr) - { - u32 dummy_gate = ++dummy_gate_counter; - for (const auto& dst_gate : dst_gates) - { - VECTOR(edges)[edge_vertex_counter++] = dummy_gate; - VECTOR(edges)[edge_vertex_counter++] = dst_gate->get_id() - 1; - - log_debug("graph_algorithm", "input_gate: {} --> {}: {}", dummy_gate, dst_gate->get_id() - 1, dst_gate->get_name().c_str()); - } - } - // if gate has no dsts --> add dummy node - else if (dst_gates.size() == 0) - { - VECTOR(edges)[edge_vertex_counter++] = src_gate->get_id() - 1; - VECTOR(edges)[edge_vertex_counter++] = ++dummy_gate_counter; - - log_debug("graph_algorithm", "{}: {} --> {} output\n", src_gate->get_name().c_str(), src_gate->get_id() - 1, dummy_gate_counter); - } - // default mode - else - { - for (const auto& dst_gate : dst_gates) - { - VECTOR(edges)[edge_vertex_counter++] = src_gate->get_id() - 1; - VECTOR(edges)[edge_vertex_counter++] = dst_gate->get_id() - 1; - - log_debug("graph_algorithm", "{}: {} --> {}: {}", src_gate->get_name().c_str(), src_gate->get_id() - 1, dst_gate->get_id() - 1, dst_gate->get_name().c_str()); - } - } - } - - igraph_create(graph, &edges, 0, IGRAPH_DIRECTED); - igraph_vector_int_destroy(&edges); - - // map with vertice id to hal-gate - std::map vertex_to_gate; - for (auto const& gate : nl->get_gates()) - { - vertex_to_gate[gate->get_id() - 1] = gate; - } - - return vertex_to_gate; - } - - std::map> GraphAlgorithmPlugin::get_memberships_for_hal(igraph_t* graph, igraph_vector_int_t *membership, std::map vertex_to_gate) - { - // map back to HAL structures - int vertices_num = (int)igraph_vcount(graph); - std::map> community_sets; - - for (int i = 0; i < vertices_num; i++) - { - auto gate = vertex_to_gate[i]; - if (gate == nullptr) - continue; - community_sets[VECTOR(*membership)[i]].insert(gate); - } - return community_sets; - } -} // namespace hal diff --git a/plugins/graph_algorithm/src/netlist_graph.cpp b/plugins/graph_algorithm/src/netlist_graph.cpp new file mode 100644 index 00000000000..9b0a792b2de --- /dev/null +++ b/plugins/graph_algorithm/src/netlist_graph.cpp @@ -0,0 +1,252 @@ +#include "graph_algorithm/netlist_graph.h" + +#include "hal_core/netlist/endpoint.h" +#include "hal_core/netlist/gate.h" +#include "hal_core/netlist/net.h" +#include "hal_core/netlist/netlist.h" + +namespace hal +{ + namespace graph_algorithm + { + NetlistGraph::NetlistGraph(Netlist* nl) : m_nl(nl) + { + } + + NetlistGraph::~NetlistGraph() + { + igraph_destroy(m_graph); + } + + Result> NetlistGraph::from_netlist(Netlist* nl, bool create_dummy_nodes, const std::function& filter) + { + auto graph = std::unique_ptr(new NetlistGraph(nl)); + + // count all edges as this number is needed to create a new graph + u32 edge_counter = 0; + for (const auto* net : graph->m_nl->get_nets(filter)) + { + std::vector src_gates; + for (const auto* src_ep : net->get_sources()) + { + src_gates.push_back(src_ep->get_gate()); + } + + std::vector dst_gates; + for (const auto* dst_ep : net->get_destinations()) + { + dst_gates.push_back(dst_ep->get_gate()); + } + + if (src_gates.empty() && create_dummy_nodes) + { + // if no sources, add one dummy edge for every destination + // all dummy edges will come from the same dummy node + edge_counter += dst_gates.size(); + } + else if (dst_gates.empty() && create_dummy_nodes) + { + // if no destinations, add one dummy edge for every source + // all dummy edges will go to the same dummy node + edge_counter += src_gates.size(); + } + else + { + // add one edge for every source-destination pair + edge_counter += dst_gates.size() * src_gates.size(); + } + } + + // initialize edge vector + igraph_vector_int_t edges; + auto err = igraph_vector_int_init(&edges, 2 * edge_counter); + if (err != IGRAPH_SUCCESS) + { + igraph_vector_int_destroy(&edges); + return ERR(igraph_strerror(err)); + } + + // we need dummy gates for input/outputs + u32 node_counter = 0; + u32 edge_index = 0; + + for (auto* g : graph->m_nl->get_gates()) + { + u32 node = node_counter++; + graph->m_gates_to_nodes[g] = node; + graph->m_nodes_to_gates[node] = g; + } + + for (const auto* net : graph->m_nl->get_nets(filter)) + { + std::vector src_gates; + for (const auto* src_ep : net->get_sources()) + { + src_gates.push_back(src_ep->get_gate()); + } + + std::vector dst_gates; + for (const auto* dst_ep : net->get_destinations()) + { + dst_gates.push_back(dst_ep->get_gate()); + } + + if (src_gates.empty() && create_dummy_nodes) + { + // if no sources, add one dummy node + u32 dummy_node = ++node_counter; + graph->m_nodes_to_gates[dummy_node] = nullptr; + for (auto* dst_gate : dst_gates) + { + VECTOR(edges)[edge_index++] = dummy_node; + VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(dst_gate); + } + } + else if (dst_gates.empty() && create_dummy_nodes) + { + // if no destinations, add one dummy node + u32 dummy_node = ++node_counter; + graph->m_nodes_to_gates[dummy_node] = nullptr; + for (auto* src_gate : src_gates) + { + VECTOR(edges)[edge_index++] = dummy_node; + VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(src_gate); + } + } + else + { + for (auto* dst_gate : dst_gates) + { + for (auto* src_gate : src_gates) + { + VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(src_gate); + VECTOR(edges)[edge_index++] = graph->m_gates_to_nodes.at(dst_gate); + } + } + } + } + + err = igraph_create(graph->m_graph, &edges, node_counter, IGRAPH_DIRECTED); + igraph_vector_int_destroy(&edges); + + if (err != IGRAPH_SUCCESS) + { + return ERR(igraph_strerror(err)); + } + + return OK(std::move(graph)); + } + + Netlist* NetlistGraph::get_netlist() const + { + return m_nl; + } + + igraph_t* NetlistGraph::get_graph() const + { + return m_graph; + } + + Result NetlistGraph::get_gate_of_vertex(const u32 node) const + { + if (!m_nl) + { + return ERR("graph does not correspond to a netlist"); + } + + if (const auto it = m_nodes_to_gates.find(node); it != m_nodes_to_gates.end()) + { + Gate* g = it->second; + if (g != nullptr) + { + return OK(g); + } + else + { + log_warning("graph_algorithm", "no gate exists for dummy node {}", node); + } + } + else + { + return ERR("no gate for node " + std::to_string(node) + " exists in netlist with ID " + std::to_string(m_nl->get_id())); + } + } + + Result> NetlistGraph::get_gates_of_vertices(const std::set& nodes) const + { + if (!m_nl) + { + return ERR("graph does not correspond to a netlist"); + } + + std::vector res; + for (const auto& node : nodes) + { + if (const auto it = m_nodes_to_gates.find(node); it != m_nodes_to_gates.end()) + { + Gate* g = it->second; + if (g != nullptr) + { + res.push_back(g); + } + else + { + log_warning("graph_algorithm", "no gate exists for dummy node {}", node); + } + } + else + { + return ERR("no gate for node " + std::to_string(node) + " exists in netlist with ID " + std::to_string(m_nl->get_id())); + } + } + return OK(res); + } + + Result> NetlistGraph::get_gates_of_vertices(const std::vector& nodes) const + { + if (!m_nl) + { + return ERR("graph does not correspond to a netlist"); + } + + std::vector res; + for (const auto& node : nodes) + { + if (const auto it = m_nodes_to_gates.find(node); it != m_nodes_to_gates.end()) + { + Gate* g = it->second; + if (g != nullptr) + { + res.push_back(g); + } + else + { + log_warning("graph_algorithm", "no gate exists for dummy node {}", node); + } + } + else + { + return ERR("no gate for node " + std::to_string(node) + " exists in netlist with ID " + std::to_string(m_nl->get_id())); + } + } + return OK(res); + } + + Result NetlistGraph::get_vertex_of_gate(Gate* g) const + { + if (!m_nl) + { + return ERR("graph does not correspond to a netlist"); + } + + if (const auto it = m_gates_to_nodes.find(g); it != m_gates_to_nodes.end()) + { + return OK(it->second); + } + else + { + return ERR("no node for gate '" + g->get_name() + "' with ID " + std::to_string(g->get_id()) + " exists in netlist with ID " + std::to_string(m_nl->get_id())); + } + } + } // namespace graph_algorithm +} // namespace hal \ No newline at end of file