diff --git a/plugins/graph_algorithm/include/graph_algorithm/algorithms/subgraph.h b/plugins/graph_algorithm/include/graph_algorithm/algorithms/subgraph.h new file mode 100644 index 00000000000..0c3cf57b9af --- /dev/null +++ b/plugins/graph_algorithm/include/graph_algorithm/algorithms/subgraph.h @@ -0,0 +1,69 @@ +// 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 +{ + class Gate; + + namespace graph_algorithm + { + class NetlistGraph; + + /** + * Compute the subgraph induced by the specified gates, including all edges between the corresponding vertices. + * + * @param[in] graph - The netlist graph. + * @param[in] subgraph_gates - A vector of gates that make up the subgraph. + * @returns The subgraph as a new netlist graph on success, an error otherwise. + */ + Result> get_subgraph(NetlistGraph* graph, const std::vector& subgraph_gates); + + /** + * Compute the subgraph induced by the specified vertices, including all edges between these vertices. + * + * @param[in] graph - The netlist graph. + * @param[in] subgraph_vertices - A vector of vertices that make up the subgraph. + * @returns The subgraph as a new netlist graph on success, an error otherwise. + */ + Result> get_subgraph(NetlistGraph* graph, const std::vector& subgraph_vertices); + + /** + * Compute the subgraph induced by the specified vertices, including all edges between these vertices. + * + * @param[in] graph - The netlist graph. + * @param[in] subgraph_vertices - An igraph vector of vertices that make up the subgraph. + * @returns The subgraph as a new netlist graph on success, an error otherwise. + */ + Result> get_subgraph_igraph(NetlistGraph* graph, const igraph_vector_int_t* subgraph_vertices); + } // namespace graph_algorithm +} // namespace hal \ No newline at end of file diff --git a/plugins/graph_algorithm/python/python_bindings.cpp b/plugins/graph_algorithm/python/python_bindings.cpp index 0fd1cfcbf2a..57a51634b9a 100644 --- a/plugins/graph_algorithm/python/python_bindings.cpp +++ b/plugins/graph_algorithm/python/python_bindings.cpp @@ -3,6 +3,7 @@ #include "graph_algorithm/algorithms/components.h" #include "graph_algorithm/algorithms/neighborhood.h" +#include "graph_algorithm/algorithms/subgraph.h" #include "graph_algorithm/netlist_graph.h" #include "graph_algorithm/plugin_graph_algorithm.h" @@ -527,6 +528,56 @@ namespace hal :rtype: list[list[int]] or None )"); + m.def( + "get_subgraph", + [](graph_algorithm::NetlistGraph* graph, const std::vector& subgraph_gates) -> std::optional> { + auto res = graph_algorithm::get_subgraph(graph, subgraph_gates); + if (res.is_ok()) + { + return res.get(); + } + else + { + log_error("python_context", "error encountered while computing subgraph:\n{}", res.get_error().get()); + return std::nullopt; + } + }, + py::arg("graph"), + py::arg("subgraph_gates"), + R"( + Compute the subgraph induced by the specified gates, including all edges between the corresponding vertices. + + :param graph_algorithm.NetlistGraph graph: The netlist graph. + :param list[hal_py.Gate] subgraph_gates: A list of gates that make up the subgraph. + :returns: The subgraph as a new netlist graph on success, ``None`` otherwise. + :rtype: graph_algorithm.NetlistGraph or None + )"); + + m.def( + "get_subgraph", + [](graph_algorithm::NetlistGraph* graph, const std::vector& subgraph_vertices) -> std::optional> { + auto res = graph_algorithm::get_subgraph(graph, subgraph_vertices); + if (res.is_ok()) + { + return res.get(); + } + else + { + log_error("python_context", "error encountered while computing subgraph:\n{}", res.get_error().get()); + return std::nullopt; + } + }, + py::arg("graph"), + py::arg("subgraph_vertices"), + R"( + Compute the subgraph induced by the specified vertices, including all edges between these vertices. + + :param graph_algorithm.NetlistGraph graph: The netlist graph. + :param list[int] subgraph_vertices: A list of vertices that make up the subgraph. + :returns: The subgraph as a new netlist graph on success, ``None`` otherwise. + :rtype: graph_algorithm.NetlistGraph or None + )"); + // .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. diff --git a/plugins/graph_algorithm/src/algorithms/subgraph.cpp b/plugins/graph_algorithm/src/algorithms/subgraph.cpp new file mode 100644 index 00000000000..11b50a1ad07 --- /dev/null +++ b/plugins/graph_algorithm/src/algorithms/subgraph.cpp @@ -0,0 +1,134 @@ +#include "graph_algorithm/algorithms/subgraph.h" + +#include "graph_algorithm/netlist_graph.h" +#include "hal_core/netlist/gate.h" + +namespace hal +{ + namespace graph_algorithm + { + Result> get_subgraph(NetlistGraph* graph, const std::vector& subgraph_gates) + { + if (graph == nullptr) + { + return ERR("graph is a nullptr"); + } + + if (subgraph_gates.empty()) + { + return ERR("no subgraph gates provided"); + } + + igraph_vector_int_t i_gates; + if (auto res = graph->get_vertices_from_gates_igraph(subgraph_gates); res.is_ok()) + { + i_gates = std::move(res.get()); + } + else + { + return ERR(res.get_error()); + } + + auto res = get_subgraph_igraph(graph, &i_gates); + + igraph_vector_int_destroy(&i_gates); + + if (res.is_error()) + { + return ERR(res.get_error()); + } + + return res; + } + + Result> get_subgraph(NetlistGraph* graph, const std::vector& subgraph_vertices) + { + if (graph == nullptr) + { + return ERR("graph is a nullptr"); + } + + if (subgraph_vertices.empty()) + { + return ERR("no subgraph vertices provided"); + } + + igraph_vector_int_t i_gates; + if (auto res = igraph_vector_int_init(&i_gates, subgraph_vertices.size()); res != IGRAPH_SUCCESS) + { + return ERR(igraph_strerror(res)); + } + + for (u32 i = 0; i < subgraph_vertices.size(); i++) + { + VECTOR(i_gates)[i] = subgraph_vertices.at(i); + } + + auto res = get_subgraph_igraph(graph, &i_gates); + + igraph_vector_int_destroy(&i_gates); + + if (res.is_error()) + { + return ERR(res.get_error()); + } + + return res; + } + + Result> get_subgraph_igraph(NetlistGraph* graph, const igraph_vector_int_t* subgraph_vertices) + { + if (graph == nullptr) + { + return ERR("graph is a nullptr"); + } + + igraph_vs_t v_sel; + if (auto res = igraph_vs_vector(&v_sel, subgraph_vertices); res != IGRAPH_SUCCESS) + { + return ERR(igraph_strerror(res)); + } + + u32 subgraph_size = igraph_vector_int_size(subgraph_vertices); + + igraph_vector_int_t i_vertex_map; + if (auto res = igraph_vector_int_init(&i_vertex_map, subgraph_size); res != IGRAPH_SUCCESS) + { + igraph_vs_destroy(&v_sel); + return ERR(igraph_strerror(res)); + } + + igraph_t i_subg; + if (const auto res = igraph_induced_subgraph_map(graph->get_graph(), &i_subg, v_sel, IGRAPH_SUBGRAPH_AUTO, nullptr, &i_vertex_map); res != IGRAPH_SUCCESS) + { + igraph_vs_destroy(&v_sel); + igraph_vector_int_destroy(&i_vertex_map); + return ERR(igraph_strerror(res)); + } + + std::unordered_map nodes_to_gates; + if (const auto res = graph->get_gates_from_vertices_igraph(&i_vertex_map); res.is_ok()) + { + std::vector gates = res.get(); + for (u32 i = 0; i < gates.size(); i++) + { + nodes_to_gates[i] = gates.at(i); + } + } + else + { + igraph_destroy(&i_subg); + igraph_vs_destroy(&v_sel); + igraph_vector_int_destroy(&i_vertex_map); + return ERR(res.get_error()); + } + + auto subgraph = std::unique_ptr(new NetlistGraph(graph->get_netlist(), std::move(i_subg), std::move(nodes_to_gates))); + + igraph_vs_destroy(&v_sel); + igraph_vector_int_destroy(&i_vertex_map); + + return OK(std::move(subgraph)); + } + } // namespace graph_algorithm +} // namespace hal \ No newline at end of file