Merge pull request #2381 from polgreen/depth_limited_search
Depth limited search
This commit is contained in:
commit
b9014de31f
|
@ -70,3 +70,29 @@ std::set<irep_idt> get_reaching_functions(
|
|||
{
|
||||
return get_connected_functions(graph, function, false);
|
||||
}
|
||||
|
||||
std::set<irep_idt> get_functions_reachable_within_n_steps(
|
||||
const call_grapht::directed_grapht &graph,
|
||||
const std::set<irep_idt> &start_functions,
|
||||
std::size_t &n)
|
||||
{
|
||||
std::vector<std::size_t> start_indices;
|
||||
std::set<irep_idt> result;
|
||||
|
||||
for(const auto &func : start_functions)
|
||||
start_indices.push_back(*(graph.get_node_index(func)));
|
||||
|
||||
for(const auto &index : graph.depth_limited_search(start_indices, n))
|
||||
result.insert(graph[index].function);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::set<irep_idt> get_functions_reachable_within_n_steps(
|
||||
const call_grapht::directed_grapht &graph,
|
||||
const irep_idt &start_function,
|
||||
std::size_t &n)
|
||||
{
|
||||
std::set<irep_idt> start_functions({ start_function });
|
||||
return get_functions_reachable_within_n_steps(graph, start_functions, n);
|
||||
}
|
||||
|
|
|
@ -49,4 +49,28 @@ std::set<irep_idt> get_reachable_functions(
|
|||
std::set<irep_idt> get_reaching_functions(
|
||||
const call_grapht::directed_grapht &graph, const irep_idt &function);
|
||||
|
||||
/// Get either callers or callees reachable from a given
|
||||
/// list of functions within N steps
|
||||
/// \param graph: call graph
|
||||
/// \param start_functions: set of start functions
|
||||
/// \param n: number of steps to consider
|
||||
/// \return set of functions that can be reached from the start function
|
||||
/// including the start function
|
||||
std::set<irep_idt> get_functions_reachable_within_n_steps(
|
||||
const call_grapht::directed_grapht &graph,
|
||||
const std::set<irep_idt> &start_functions,
|
||||
std::size_t &n);
|
||||
|
||||
/// Get either callers or callees reachable from a given
|
||||
/// list of functions within N steps
|
||||
/// \param graph: call graph
|
||||
/// \param start_function: single start function
|
||||
/// \param n: number of steps to consider
|
||||
/// \return set of functions that can be reached from the start function
|
||||
/// including the start function
|
||||
std::set<irep_idt> get_functions_reachable_within_n_steps(
|
||||
const call_grapht::directed_grapht &graph,
|
||||
const irep_idt &start_function,
|
||||
std::size_t &n);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -255,6 +255,18 @@ public:
|
|||
void disconnect_unreachable(node_indext src);
|
||||
void disconnect_unreachable(const std::vector<node_indext> &src);
|
||||
|
||||
std::vector<node_indext> depth_limited_search(
|
||||
const node_indext &src,
|
||||
std::size_t &limit,
|
||||
bool forwards) const;
|
||||
|
||||
std::vector<typename N::node_indext>
|
||||
depth_limited_search(typename N::node_indext src, std::size_t limit) const;
|
||||
|
||||
std::vector<typename N::node_indext> depth_limited_search(
|
||||
std::vector<typename N::node_indext> &src,
|
||||
std::size_t limit) const;
|
||||
|
||||
void make_chordal();
|
||||
|
||||
// return value: number of connected subgraphs
|
||||
|
@ -278,6 +290,11 @@ public:
|
|||
std::function<void(const node_indext &)> f) const;
|
||||
|
||||
protected:
|
||||
std::vector<typename N::node_indext> depth_limited_search(
|
||||
std::vector<typename N::node_indext> &src,
|
||||
std::size_t limit,
|
||||
std::vector<bool> &visited) const;
|
||||
|
||||
class tarjant
|
||||
{
|
||||
public:
|
||||
|
@ -584,6 +601,83 @@ std::vector<typename N::node_indext> grapht<N>::get_reachable(
|
|||
return result;
|
||||
}
|
||||
|
||||
/// Run recursive depth-limited search on the graph, starting
|
||||
/// from multiple source nodes, to find the nodes reachable within n steps.
|
||||
/// This function initialises the search.
|
||||
/// \param src The node to start the search from.
|
||||
/// \param limit limit on steps
|
||||
/// \return a vector of reachable node indices
|
||||
template <class N>
|
||||
std::vector<typename N::node_indext> grapht<N>::depth_limited_search(
|
||||
const typename N::node_indext src,
|
||||
std::size_t limit) const
|
||||
{
|
||||
std::vector<node_indext> start_vector(1, src);
|
||||
return depth_limited_search(start_vector, limit);
|
||||
}
|
||||
|
||||
/// Run recursive depth-limited search on the graph, starting
|
||||
/// from multiple source nodes, to find the nodes reachable within n steps.
|
||||
/// This function initialises the search.
|
||||
/// \param src The nodes to start the search from.
|
||||
/// \param limit limit on steps
|
||||
/// \return a vector of reachable node indices
|
||||
template <class N>
|
||||
std::vector<typename N::node_indext> grapht<N>::depth_limited_search(
|
||||
std::vector<typename N::node_indext> &src,
|
||||
std::size_t limit) const
|
||||
{
|
||||
std::vector<bool> visited(nodes.size(), false);
|
||||
|
||||
for(const auto &node : src)
|
||||
{
|
||||
PRECONDITION(node < nodes.size());
|
||||
visited[node] = true;
|
||||
}
|
||||
|
||||
return depth_limited_search(src, limit, visited);
|
||||
}
|
||||
|
||||
/// Run recursive depth-limited search on the graph, starting
|
||||
// from multiple source nodes, to find the nodes reachable within n steps
|
||||
/// \param src The nodes to start the search from.
|
||||
/// \param limit limit on steps
|
||||
/// \param visited vector of booleans indicating whether a node has been visited
|
||||
/// \return a vector of reachable node indices
|
||||
template <class N>
|
||||
std::vector<typename N::node_indext> grapht<N>::depth_limited_search(
|
||||
std::vector<typename N::node_indext> &src,
|
||||
std::size_t limit,
|
||||
std::vector<bool> &visited) const
|
||||
{
|
||||
if(limit == 0)
|
||||
return src;
|
||||
|
||||
std::vector<node_indext> next_ring;
|
||||
|
||||
for(const auto &n : src)
|
||||
{
|
||||
for(const auto &o : nodes[n].out)
|
||||
{
|
||||
if(!visited[o.first])
|
||||
{
|
||||
next_ring.push_back(o.first);
|
||||
visited[o.first] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(next_ring.empty())
|
||||
return src;
|
||||
|
||||
limit--;
|
||||
|
||||
for(const auto &succ : depth_limited_search(next_ring, limit, visited))
|
||||
src.push_back(succ);
|
||||
|
||||
return src;
|
||||
}
|
||||
|
||||
template<class N>
|
||||
std::size_t grapht<N>::connected_subgraphs(
|
||||
std::vector<node_indext> &subgraph_nr)
|
||||
|
|
|
@ -223,6 +223,48 @@ SCENARIO("call_graph",
|
|||
REQUIRE(exported.has_edge(nodes_by_name["B"], nodes_by_name["D"]));
|
||||
}
|
||||
|
||||
THEN("We expect {A,B} to be reachable from {A} in 1 step")
|
||||
{
|
||||
irep_idt function_name = "A";
|
||||
std::size_t depth = 1;
|
||||
std::set<irep_idt> reachable = get_functions_reachable_within_n_steps(
|
||||
exported, function_name, depth);
|
||||
REQUIRE(reachable.size() == 2);
|
||||
REQUIRE(reachable.count("A"));
|
||||
REQUIRE(reachable.count("B"));
|
||||
}
|
||||
THEN("We expect {A,B,C,D} to be reachable from {A} in 2 and 3 steps")
|
||||
{
|
||||
irep_idt function_name = "A";
|
||||
std::size_t depth = 2;
|
||||
std::set<irep_idt> reachable = get_functions_reachable_within_n_steps(
|
||||
exported, function_name, depth);
|
||||
REQUIRE(reachable.size() == 4);
|
||||
REQUIRE(reachable.count("A"));
|
||||
REQUIRE(reachable.count("B"));
|
||||
REQUIRE(reachable.count("C"));
|
||||
REQUIRE(reachable.count("D"));
|
||||
|
||||
depth = 3;
|
||||
reachable = get_functions_reachable_within_n_steps(
|
||||
exported, function_name, depth);
|
||||
REQUIRE(reachable.size() == 4);
|
||||
REQUIRE(reachable.count("A"));
|
||||
REQUIRE(reachable.count("B"));
|
||||
REQUIRE(reachable.count("C"));
|
||||
REQUIRE(reachable.count("D"));
|
||||
}
|
||||
|
||||
THEN("We expect only {A} to be reachable from {A} in 0 steps")
|
||||
{
|
||||
irep_idt function_name = "A";
|
||||
std::size_t depth = 0;
|
||||
std::set<irep_idt> reachable = get_functions_reachable_within_n_steps(
|
||||
exported, function_name, depth);
|
||||
REQUIRE(reachable.size() == 1);
|
||||
REQUIRE(reachable.count("A"));
|
||||
}
|
||||
|
||||
THEN("We expect A to have successors {A, B}")
|
||||
{
|
||||
std::set<irep_idt> successors = get_callees(exported, "A");
|
||||
|
|
Loading…
Reference in New Issue