Skip to main content
Code Review

Return to Question

replaced http://codereview.stackexchange.com/ with https://codereview.stackexchange.com/
Source Link

(This is a follow on to this question this question).

(This is a follow on to this question).

(This is a follow on to this question).

Tweeted twitter.com/#!/StackCodeReview/status/483747001679745024
unwanted whitespace creeping in
Source Link
Yuushi
  • 11.1k
  • 2
  • 31
  • 66
/*! \file graph_degree.hpp
 * \brief Algorithms relating to node degree.
 *
 * Defines core algorithms to investigate indegree and 
 * outdegrees concerning a given graph. This includes finding minimum, 
 * maximum, average, and the distribution over a whole graph. It also has 
 * algorithms specifically for finding disonnected nodes (defined as nodes
 * with 0 indegree, that is, inaccessible nodes), and sink nodes (defined as
 * nodes with 0 outdegree, that is, nodes one cannot leave). 
 *
 * \addtogroup graph_algorithm
 * @{
*/
#ifndef GRAPH_DEGREE_SGL_HPP_
#define GRAPH_DEGREE_SGL_HPP_
#include <functional>
#include <limits>
#include <map>
#include <utility>
#include <vector>
#include "boost/optional.hpp"
namespace simplegl
{
namespace graph
{
namespace
{
//Since max and min outdegree differ only by the comparator they use,
//and indegree and outdegree differ only by functon call,
//this is the core functionality abstracted out.
template <typename Graph, typename Compare, typename Selector>
boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
>
find_degree(const Graph& g, Compare comparator, Selector degree_type)
{
 using node_type = typename Graph::node_type;
 using optional_t = 
 boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
 >;
 if(g.empty()) { 
 return optional_t();
 }
 auto t = g.begin()->first;
 auto current = degree_type(t);
 auto degree = current;
 
 auto begin = g.begin();
 std::advance(begin, 1);
 for(auto it = begin; it != g.end(); ++it) {
 current = degree_type(it->first);
 if(comparator(current, degree)) {
 degree = current;
 t = it->first;
 }
 }
 return optional_t(std::make_pair(t, degree));
}
template <typename Graph>
using optional_t = 
 boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
 >;
template <typename Graph, typename Compare>
optional_t<Graph> find_outdegree(const Graph& g, Compare comparator)
{
 using node_type = typename Graph::node_type;
 auto select_type = [&](const node_type& n) { return g.outdegree(n); };
 return find_degree(g, comparator, select_type); 
}
template <typename Graph, typename Compare>
optional_t<Graph> find_indegree(const Graph& g, Compare comparator)
{
 using node_type = typename Graph::node_type;
 auto select_type = [&](const node_type& n) { return g.indegree(n); };
 return find_degree(g, comparator, select_type); 
}
} // end unnamed namespace
/*! \brief Finds the node with maximum outdegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with maximum outdegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * maximum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> max_outdegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_outdegree(g, std::greater<size_type>());
}
/*! \brief Finds the node with minimum outdegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with minimum outdegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * minimum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> min_outdegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_outdegree(g, std::less<size_type>());
}
/*! \brief Finds the node with maximum indegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with maximum indegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * maximum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> max_indegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_indegree(g, std::greater<size_type>());
}
/*! \brief Finds the node with minimum indegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with minimum indegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * minimum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> min_indegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_indegree(g, std::less<size_type>());
}
/*! \brief Returns the average indegree of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A double, represending the average indegree of <B>g</B>.
*/
template <typename Graph>
double average_indegree(const Graph& g)
{
 double start = 0;
 typename Graph::size_type total_nodes = 0;
 
 for(auto it = g.begin(); it != g.end(); ++it) {
 start += g.indegree(it->first);
 ++total_nodes;
 }
 
 return start/total_nodes;
}
/*! \brief Returns the average outdegree of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A double, represending the average outdegree of <B>g</B>.
*/
template <typename Graph>
double average_outdegree(const Graph& g)
{
 double start = 0;
 typename Graph::size_type total_nodes = 0;
 
 for(auto it = g.begin(); it != g.end(); ++it) {
 start += g.indegree(it->first);
 ++total_nodes;
 }
 
 return start/total_nodes;
}
/*! \brief Returns the distribution of outdegrees over of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A std::map<typename Graph::size_type, typename Graph::size_type>
 * containing pairs of type <I>{outdegree : count of nodes with given outdegree}</I>.
*/
template <typename Graph>
std::map<typename Graph::size_type, typename Graph::size_type>
outdegree_distribution(const Graph& g)
{
 std::map<typename Graph::size_type, typename Graph::size_type> mp;
 for(auto it = g.begin(); it != g.end(); ++it) {
 mp[g.outdegree(it->first)] += 1;
 }
 return mp;
}
/*! \brief Returns the distribution of indegrees over of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A std::map<typename Graph::size_type, typename Graph::size_type>
 * containing pairs of type <I>{indegree : count of nodes with given indegree}</I>.
*/
template <typename Graph>
std::map<typename Graph::size_type, typename Graph::size_type>
indegree_distribution(const Graph& g)
{
 std::map<typename Graph::size_type, typename Graph::size_type> mp;
 for(auto it = g.begin(); it != g.end(); ++it) {
 mp[g.indegree(it->first)] += 1;
 }
 return mp;
}
/*! \brief Finds all disconnected nodes of the given graph, inserting them into ii.
 * 
 * \param g The graph to search over.
 * \param ii An input iterator into a container that will hold the nodes that are
 found to be disconnected.
 * \return The number of disconnected nodes found.
*/ 
template <typename Graph, typename Iterator>
std::size_t disconnected_nodes(const Graph& g, Iterator ii)
{
 std::size_t num_disconnected = 0;
 for(auto it = g.begin(); it != g.end(); ++it) {
 if(g.indegree(it->first) == 0) {
 ii = it->first;
 ++num_disconnected;
 }
 }
 return num_disconnected;
}
/*! \brief Finds all sink nodes (nodes with outdegree 0) of the given graph, 
 * inserting them into ii.
 * 
 * \param g The graph to search over.
 * \param ii An input iterator into a container that will hold the nodes that are
 found to be sinks.
 * \return The number of sink nodes found.
*/ 
template <typename Graph, typename Iterator>
std::size_t sink_nodes(const Graph& g, Iterator ii)
{
 std::size_t num_sink = 0;
 for(auto it = g.begin(); it != g.end(); ++it) {
 if(g.outdegree(it->first) == 0) {
 ii = it->first;
 ++num_sink;
 }
 }
 return num_sink;
}
} //end namespace graph
} //end namespace simplegl
#endif //GRAPH_DEGREE_SGL_HPP_
/*! @} End of Doxygen Group graph_algorithm */
/*! \file graph_degree.hpp
 * \brief Algorithms relating to node degree.
 *
 * Defines core algorithms to investigate indegree and 
 * outdegrees concerning a given graph. This includes finding minimum, 
 * maximum, average, and the distribution over a whole graph. It also has 
 * algorithms specifically for finding disonnected nodes (defined as nodes
 * with 0 indegree, that is, inaccessible nodes), and sink nodes (defined as
 * nodes with 0 outdegree, that is, nodes one cannot leave). 
 *
 * \addtogroup graph_algorithm
 * @{
*/
#ifndef GRAPH_DEGREE_SGL_HPP_
#define GRAPH_DEGREE_SGL_HPP_
#include <functional>
#include <limits>
#include <map>
#include <utility>
#include <vector>
#include "boost/optional.hpp"
namespace simplegl
{
namespace graph
{
namespace
{
//Since max and min outdegree differ only by the comparator they use,
//and indegree and outdegree differ only by functon call,
//this is the core functionality abstracted out.
template <typename Graph, typename Compare, typename Selector>
boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
>
find_degree(const Graph& g, Compare comparator, Selector degree_type)
{
 using node_type = typename Graph::node_type;
 using optional_t = 
 boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
 >;
 if(g.empty()) { 
 return optional_t();
 }
 auto t = g.begin()->first;
 auto current = degree_type(t);
 auto degree = current;
 
 auto begin = g.begin();
 std::advance(begin, 1);
 for(auto it = begin; it != g.end(); ++it) {
 current = degree_type(it->first);
 if(comparator(current, degree)) {
 degree = current;
 t = it->first;
 }
 }
 return optional_t(std::make_pair(t, degree));
}
template <typename Graph>
using optional_t = 
 boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
 >;
template <typename Graph, typename Compare>
optional_t<Graph> find_outdegree(const Graph& g, Compare comparator)
{
 using node_type = typename Graph::node_type;
 auto select_type = [&](const node_type& n) { return g.outdegree(n); };
 return find_degree(g, comparator, select_type); 
}
template <typename Graph, typename Compare>
optional_t<Graph> find_indegree(const Graph& g, Compare comparator)
{
 using node_type = typename Graph::node_type;
 auto select_type = [&](const node_type& n) { return g.indegree(n); };
 return find_degree(g, comparator, select_type); 
}
} // end unnamed namespace
/*! \brief Finds the node with maximum outdegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with maximum outdegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * maximum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> max_outdegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_outdegree(g, std::greater<size_type>());
}
/*! \brief Finds the node with minimum outdegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with minimum outdegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * minimum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> min_outdegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_outdegree(g, std::less<size_type>());
}
/*! \brief Finds the node with maximum indegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with maximum indegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * maximum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> max_indegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_indegree(g, std::greater<size_type>());
}
/*! \brief Finds the node with minimum indegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with minimum indegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * minimum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> min_indegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_indegree(g, std::less<size_type>());
}
/*! \brief Returns the average indegree of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A double, represending the average indegree of <B>g</B>.
*/
template <typename Graph>
double average_indegree(const Graph& g)
{
 double start = 0;
 typename Graph::size_type total_nodes = 0;
 
 for(auto it = g.begin(); it != g.end(); ++it) {
 start += g.indegree(it->first);
 ++total_nodes;
 }
 
 return start/total_nodes;
}
/*! \brief Returns the average outdegree of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A double, represending the average outdegree of <B>g</B>.
*/
template <typename Graph>
double average_outdegree(const Graph& g)
{
 double start = 0;
 typename Graph::size_type total_nodes = 0;
 
 for(auto it = g.begin(); it != g.end(); ++it) {
 start += g.indegree(it->first);
 ++total_nodes;
 }
 
 return start/total_nodes;
}
/*! \brief Returns the distribution of outdegrees over of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A std::map<typename Graph::size_type, typename Graph::size_type>
 * containing pairs of type <I>{outdegree : count of nodes with given outdegree}</I>.
*/
template <typename Graph>
std::map<typename Graph::size_type, typename Graph::size_type>
outdegree_distribution(const Graph& g)
{
 std::map<typename Graph::size_type, typename Graph::size_type> mp;
 for(auto it = g.begin(); it != g.end(); ++it) {
 mp[g.outdegree(it->first)] += 1;
 }
 return mp;
}
/*! \brief Returns the distribution of indegrees over of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A std::map<typename Graph::size_type, typename Graph::size_type>
 * containing pairs of type <I>{indegree : count of nodes with given indegree}</I>.
*/
template <typename Graph>
std::map<typename Graph::size_type, typename Graph::size_type>
indegree_distribution(const Graph& g)
{
 std::map<typename Graph::size_type, typename Graph::size_type> mp;
 for(auto it = g.begin(); it != g.end(); ++it) {
 mp[g.indegree(it->first)] += 1;
 }
 return mp;
}
/*! \brief Finds all disconnected nodes of the given graph, inserting them into ii.
 * 
 * \param g The graph to search over.
 * \param ii An input iterator into a container that will hold the nodes that are
 found to be disconnected.
 * \return The number of disconnected nodes found.
*/ 
template <typename Graph, typename Iterator>
std::size_t disconnected_nodes(const Graph& g, Iterator ii)
{
 std::size_t num_disconnected = 0;
 for(auto it = g.begin(); it != g.end(); ++it) {
 if(g.indegree(it->first) == 0) {
 ii = it->first;
 ++num_disconnected;
 }
 }
 return num_disconnected;
}
/*! \brief Finds all sink nodes (nodes with outdegree 0) of the given graph, 
 * inserting them into ii.
 * 
 * \param g The graph to search over.
 * \param ii An input iterator into a container that will hold the nodes that are
 found to be sinks.
 * \return The number of sink nodes found.
*/ 
template <typename Graph, typename Iterator>
std::size_t sink_nodes(const Graph& g, Iterator ii)
{
 std::size_t num_sink = 0;
 for(auto it = g.begin(); it != g.end(); ++it) {
 if(g.outdegree(it->first) == 0) {
 ii = it->first;
 ++num_sink;
 }
 }
 return num_sink;
}
} //end namespace graph
} //end namespace simplegl
#endif //GRAPH_DEGREE_SGL_HPP_
/*! @} End of Doxygen Group graph_algorithm */
/*! \file graph_degree.hpp
 * \brief Algorithms relating to node degree.
 *
 * Defines core algorithms to investigate indegree and 
 * outdegrees concerning a given graph. This includes finding minimum, 
 * maximum, average, and the distribution over a whole graph. It also has 
 * algorithms specifically for finding disonnected nodes (defined as nodes
 * with 0 indegree, that is, inaccessible nodes), and sink nodes (defined as
 * nodes with 0 outdegree, that is, nodes one cannot leave). 
 *
 * \addtogroup graph_algorithm
 * @{
*/
#ifndef GRAPH_DEGREE_SGL_HPP_
#define GRAPH_DEGREE_SGL_HPP_
#include <functional>
#include <limits>
#include <map>
#include <utility>
#include <vector>
#include "boost/optional.hpp"
namespace simplegl
{
namespace graph
{
namespace
{
//Since max and min outdegree differ only by the comparator they use,
//and indegree and outdegree differ only by functon call,
//this is the core functionality abstracted out.
template <typename Graph, typename Compare, typename Selector>
boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
>
find_degree(const Graph& g, Compare comparator, Selector degree_type)
{
 using node_type = typename Graph::node_type;
 using optional_t = 
 boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
 >;
 if(g.empty()) { 
 return optional_t();
 }
 auto t = g.begin()->first;
 auto current = degree_type(t);
 auto degree = current;
 
 auto begin = g.begin();
 std::advance(begin, 1);
 for(auto it = begin; it != g.end(); ++it) {
 current = degree_type(it->first);
 if(comparator(current, degree)) {
 degree = current;
 t = it->first;
 }
 }
 return optional_t(std::make_pair(t, degree));
}
template <typename Graph>
using optional_t = 
 boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
 >;
template <typename Graph, typename Compare>
optional_t<Graph> find_outdegree(const Graph& g, Compare comparator)
{
 using node_type = typename Graph::node_type;
 auto select_type = [&](const node_type& n) { return g.outdegree(n); };
 return find_degree(g, comparator, select_type); 
}
template <typename Graph, typename Compare>
optional_t<Graph> find_indegree(const Graph& g, Compare comparator)
{
 using node_type = typename Graph::node_type;
 auto select_type = [&](const node_type& n) { return g.indegree(n); };
 return find_degree(g, comparator, select_type); 
}
} // end unnamed namespace
/*! \brief Finds the node with maximum outdegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with maximum outdegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * maximum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> max_outdegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_outdegree(g, std::greater<size_type>());
}
/*! \brief Finds the node with minimum outdegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with minimum outdegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * minimum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> min_outdegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_outdegree(g, std::less<size_type>());
}
/*! \brief Finds the node with maximum indegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with maximum indegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * maximum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> max_indegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_indegree(g, std::greater<size_type>());
}
/*! \brief Finds the node with minimum indegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with minimum indegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * minimum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> min_indegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_indegree(g, std::less<size_type>());
}
/*! \brief Returns the average indegree of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A double, represending the average indegree of <B>g</B>.
*/
template <typename Graph>
double average_indegree(const Graph& g)
{
 double start = 0;
 typename Graph::size_type total_nodes = 0;
 
 for(auto it = g.begin(); it != g.end(); ++it) {
 start += g.indegree(it->first);
 ++total_nodes;
 }
 
 return start/total_nodes;
}
/*! \brief Returns the average outdegree of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A double, represending the average outdegree of <B>g</B>.
*/
template <typename Graph>
double average_outdegree(const Graph& g)
{
 double start = 0;
 typename Graph::size_type total_nodes = 0;
 
 for(auto it = g.begin(); it != g.end(); ++it) {
 start += g.indegree(it->first);
 ++total_nodes;
 }
 
 return start/total_nodes;
}
/*! \brief Returns the distribution of outdegrees over of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A std::map<typename Graph::size_type, typename Graph::size_type>
 * containing pairs of type <I>{outdegree : count of nodes with given outdegree}</I>.
*/
template <typename Graph>
std::map<typename Graph::size_type, typename Graph::size_type>
outdegree_distribution(const Graph& g)
{
 std::map<typename Graph::size_type, typename Graph::size_type> mp;
 for(auto it = g.begin(); it != g.end(); ++it) {
 mp[g.outdegree(it->first)] += 1;
 }
 return mp;
}
/*! \brief Returns the distribution of indegrees over of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A std::map<typename Graph::size_type, typename Graph::size_type>
 * containing pairs of type <I>{indegree : count of nodes with given indegree}</I>.
*/
template <typename Graph>
std::map<typename Graph::size_type, typename Graph::size_type>
indegree_distribution(const Graph& g)
{
 std::map<typename Graph::size_type, typename Graph::size_type> mp;
 for(auto it = g.begin(); it != g.end(); ++it) {
 mp[g.indegree(it->first)] += 1;
 }
 return mp;
}
/*! \brief Finds all disconnected nodes of the given graph, inserting them into ii.
 * 
 * \param g The graph to search over.
 * \param ii An input iterator into a container that will hold the nodes that are
 found to be disconnected.
 * \return The number of disconnected nodes found.
*/ 
template <typename Graph, typename Iterator>
std::size_t disconnected_nodes(const Graph& g, Iterator ii)
{
 std::size_t num_disconnected = 0;
 for(auto it = g.begin(); it != g.end(); ++it) {
 if(g.indegree(it->first) == 0) {
 ii = it->first;
 ++num_disconnected;
 }
 }
 return num_disconnected;
}
/*! \brief Finds all sink nodes (nodes with outdegree 0) of the given graph, 
 * inserting them into ii.
 * 
 * \param g The graph to search over.
 * \param ii An input iterator into a container that will hold the nodes that are
 found to be sinks.
 * \return The number of sink nodes found.
*/ 
template <typename Graph, typename Iterator>
std::size_t sink_nodes(const Graph& g, Iterator ii)
{
 std::size_t num_sink = 0;
 for(auto it = g.begin(); it != g.end(); ++it) {
 if(g.outdegree(it->first) == 0) {
 ii = it->first;
 ++num_sink;
 }
 }
 return num_sink;
}
} //end namespace graph
} //end namespace simplegl
#endif //GRAPH_DEGREE_SGL_HPP_
/*! @} End of Doxygen Group graph_algorithm */
Source Link
Yuushi
  • 11.1k
  • 2
  • 31
  • 66

Generic Graph Library Part 2 : Algorithms

(This is a follow on to this question).

Having given an implementation for some of the graph structures, here is a portion of the algorithms that are defined to work over them:

graph_degree.hpp

/*! \file graph_degree.hpp
 * \brief Algorithms relating to node degree.
 *
 * Defines core algorithms to investigate indegree and 
 * outdegrees concerning a given graph. This includes finding minimum, 
 * maximum, average, and the distribution over a whole graph. It also has 
 * algorithms specifically for finding disonnected nodes (defined as nodes
 * with 0 indegree, that is, inaccessible nodes), and sink nodes (defined as
 * nodes with 0 outdegree, that is, nodes one cannot leave). 
 *
 * \addtogroup graph_algorithm
 * @{
*/
#ifndef GRAPH_DEGREE_SGL_HPP_
#define GRAPH_DEGREE_SGL_HPP_
#include <functional>
#include <limits>
#include <map>
#include <utility>
#include <vector>
#include "boost/optional.hpp"
namespace simplegl
{
namespace graph
{
namespace
{
//Since max and min outdegree differ only by the comparator they use,
//and indegree and outdegree differ only by functon call,
//this is the core functionality abstracted out.
template <typename Graph, typename Compare, typename Selector>
boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
>
find_degree(const Graph& g, Compare comparator, Selector degree_type)
{
 
 using node_type = typename Graph::node_type;
 using optional_t = 
 boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
 >;
 if(g.empty()) { 
 return optional_t();
 }
 auto t = g.begin()->first;
 auto current = degree_type(t);
 auto degree = current;
 
 auto begin = g.begin();
 std::advance(begin, 1);
 for(auto it = begin; it != g.end(); ++it) {
 current = degree_type(it->first);
 if(comparator(current, degree)) {
 degree = current;
 t = it->first;
 }
 }
 return optional_t(std::make_pair(t, degree));
}
template <typename Graph>
using optional_t = 
 boost::optional<
 std::pair<typename Graph::node_type, typename Graph::size_type>
 >;
template <typename Graph, typename Compare>
optional_t<Graph> find_outdegree(const Graph& g, Compare comparator)
{
 using node_type = typename Graph::node_type;
 auto select_type = [&](const node_type& n) { return g.outdegree(n); };
 return find_degree(g, comparator, select_type); 
}
template <typename Graph, typename Compare>
optional_t<Graph> find_indegree(const Graph& g, Compare comparator)
{
 using node_type = typename Graph::node_type;
 auto select_type = [&](const node_type& n) { return g.indegree(n); };
 return find_degree(g, comparator, select_type); 
}
} // end unnamed namespace
/*! \brief Finds the node with maximum outdegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with maximum outdegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * maximum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> max_outdegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_outdegree(g, std::greater<size_type>());
}
/*! \brief Finds the node with minimum outdegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with minimum outdegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * minimum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> min_outdegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_outdegree(g, std::less<size_type>());
}
/*! \brief Finds the node with maximum indegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with maximum indegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * maximum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> max_indegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_indegree(g, std::greater<size_type>());
}
/*! \brief Finds the node with minimum indegree in the Graph g.
 * 
 * \param g The graph to search over.
 * \return A std::pair containing the node with minimum indegree as the first member,
 * and the degree count as the second member. For graphs with many nodes of equal
 * minimum degree, it is implementation dependent as to which node is chosen.
*/
template <typename Graph>
optional_t<Graph> min_indegree(const Graph& g)
{
 using size_type = typename Graph::size_type;
 return find_indegree(g, std::less<size_type>());
}
/*! \brief Returns the average indegree of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A double, represending the average indegree of <B>g</B>.
*/
template <typename Graph>
double average_indegree(const Graph& g)
{
 double start = 0;
 typename Graph::size_type total_nodes = 0;
 
 for(auto it = g.begin(); it != g.end(); ++it) {
 start += g.indegree(it->first);
 ++total_nodes;
 }
 
 return start/total_nodes;
}
/*! \brief Returns the average outdegree of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A double, represending the average outdegree of <B>g</B>.
*/
template <typename Graph>
double average_outdegree(const Graph& g)
{
 double start = 0;
 typename Graph::size_type total_nodes = 0;
 
 for(auto it = g.begin(); it != g.end(); ++it) {
 start += g.indegree(it->first);
 ++total_nodes;
 }
 
 return start/total_nodes;
}
/*! \brief Returns the distribution of outdegrees over of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A std::map<typename Graph::size_type, typename Graph::size_type>
 * containing pairs of type <I>{outdegree : count of nodes with given outdegree}</I>.
*/
template <typename Graph>
std::map<typename Graph::size_type, typename Graph::size_type>
outdegree_distribution(const Graph& g)
{
 std::map<typename Graph::size_type, typename Graph::size_type> mp;
 for(auto it = g.begin(); it != g.end(); ++it) {
 mp[g.outdegree(it->first)] += 1;
 }
 return mp;
}
/*! \brief Returns the distribution of indegrees over of all nodes in the graph.
 * 
 * \param g The graph to search over.
 * \return A std::map<typename Graph::size_type, typename Graph::size_type>
 * containing pairs of type <I>{indegree : count of nodes with given indegree}</I>.
*/
template <typename Graph>
std::map<typename Graph::size_type, typename Graph::size_type>
indegree_distribution(const Graph& g)
{
 std::map<typename Graph::size_type, typename Graph::size_type> mp;
 for(auto it = g.begin(); it != g.end(); ++it) {
 mp[g.indegree(it->first)] += 1;
 }
 return mp;
}
/*! \brief Finds all disconnected nodes of the given graph, inserting them into ii.
 * 
 * \param g The graph to search over.
 * \param ii An input iterator into a container that will hold the nodes that are
 found to be disconnected.
 * \return The number of disconnected nodes found.
*/ 
template <typename Graph, typename Iterator>
std::size_t disconnected_nodes(const Graph& g, Iterator ii)
{
 std::size_t num_disconnected = 0;
 for(auto it = g.begin(); it != g.end(); ++it) {
 if(g.indegree(it->first) == 0) {
 ii = it->first;
 ++num_disconnected;
 }
 }
 return num_disconnected;
}
/*! \brief Finds all sink nodes (nodes with outdegree 0) of the given graph, 
 * inserting them into ii.
 * 
 * \param g The graph to search over.
 * \param ii An input iterator into a container that will hold the nodes that are
 found to be sinks.
 * \return The number of sink nodes found.
*/ 
template <typename Graph, typename Iterator>
std::size_t sink_nodes(const Graph& g, Iterator ii)
{
 std::size_t num_sink = 0;
 for(auto it = g.begin(); it != g.end(); ++it) {
 if(g.outdegree(it->first) == 0) {
 ii = it->first;
 ++num_sink;
 }
 }
 return num_sink;
}
} //end namespace graph
} //end namespace simplegl
#endif //GRAPH_DEGREE_SGL_HPP_
/*! @} End of Doxygen Group graph_algorithm */

graph_search.hpp

/*! \file graph_search.hpp
 * \brief Algorithms for searching over graphs and finding connected components.
 *
 * Algorithms to investigate graph connectedness. Contains basic breadth-first 
 * and depth-first search functionality. In addition, contains tests for
 * connectedness, finding connected components, and determining whether or
 * not a graph contains a cycle from a given source node.
 *
 * \addtogroup graph_algorithm
 * @{
*/
#ifndef GRAPH_SEARCH_SGL_HPP_
#define GRAPH_SEARCH_SGL_HPP_
#include <algorithm>
#include <queue>
#include <set>
#include <stack>
namespace simplegl
{
namespace graph
{
namespace
{
//There are obvious similarities between breadth first and depth first
//searches; in fact, the algorithms are almost identical. To take advantage
//of this, we just need to wrap queue and stack with a begin() function
//which will return a reference to the first element in each. This is required
//because they use different member functions to access the first element,
//that is, front() vs top(). 
template <typename Type>
Type& begin(std::queue<Type>& q)
{
 return q.front();
}
template <typename Type>
Type& begin(std::stack<Type>& s)
{
 return s.top();
}
//Base search, which is used by both DFS and BFS
template <typename Graph, typename Iterator, typename Container>
void search_base
(const Graph& g, const typename Graph::node_type& root, Iterator ii, Container& cont)
{
 using node_type = typename Graph::node_type;
 using adj_iter = typename Graph::const_adjacency_iterator;
 std::set<node_type> examined_nodes;
 cont.push(root);
 examined_nodes.insert(root);
 ii = root;
 while(!cont.empty()) {
 node_type current_node = begin(cont);
 cont.pop();
 auto adj_nodes = g.adjacent_nodes(current_node);
 for(auto it = adj_nodes.first; it != adj_nodes.second; ++it) {
 if(examined_nodes.find(*it) == examined_nodes.end()) {
 ii = *it;
 cont.push(*it);
 examined_nodes.insert(*it);
 }
 }
 }
}
} // end unnamed namespace
/*! \brief A standard breadth first search. 
 * 
 * \param g A graph to search over.
 * \param root The root node from which to begin the search.
 * \param ii An insert iterator ii into a container, which will hold all reachable nodes
 * from <B>root</B>.
 *
*/
template <typename Graph, typename Iterator>
void 
breadth_first_search(const Graph& g, const typename Graph::node_type& root, Iterator ii)
{
 std::queue<typename Graph::node_type> q;
 search_base(g, root, ii, q);
}
/*! \brief A standard depth first search. 
 * 
 * \param g A graph to search over.
 * \param root The root node from which to begin the search.
 * \param ii An insert iterator ii into a container, which will hold all reachable nodes
 * from <B>root</B>.
 *
*/
template <typename Graph, typename Iterator>
void depth_first_search(const Graph& g, const typename Graph::node_type& root, Iterator ii)
{
 std::stack<typename Graph::node_type> s;
 search_base(g, root, ii, s);
}
/*! \brief Tests two nodes to see if there is a path between them in the given graph. 
 * 
 * \param g A graph to search over.
 * \param from The node from which to begin the search.
 * \param to The node to find a path to.
 * 
 * \return true if there is a path connecting (from, to), false otherwise.
*/
template <typename Graph>
bool is_connected(const Graph& g, const typename Graph::node_type& from, 
 const typename Graph::node_type& to)
{
 //Pathological case, if they're the same node, then they must
 //be connected.
 using key_less = typename Graph::key_compare;
 auto comp = key_less();
 if(!(comp(from, to) && !(comp(to, from)))) {
 return true;
 }
 
 //Otherwise, utilize a BFS. 
 using node_type = typename Graph::node_type;
 using adj_iter = typename Graph::const_adjacency_iterator;
 
 std::queue<node_type> to_examine;
 std::set<node_type> examined_nodes;
 
 to_examine.push(from);
 examined_nodes.insert(from);
 while(!to_examine.empty()) {
 node_type current_node = to_examine.front();
 to_examine.pop();
 auto adj_nodes = g.adjacent_nodes(current_node);
 for(auto it = adj_nodes.first; it != adj_nodes.second; ++it) {
 if(examined_nodes.find(*it) == examined_nodes.end()) {
 if(*it == to) {
 return true;
 }
 to_examine.push(*it);
 examined_nodes.insert(*it);
 }
 }
 }
 return false;
}
/*! \brief Tests to see if there is a (non-trivial) cyclic path from a given node. 
 * 
 * \param g A graph to search over.
 * \param node The node from which to begin the search.
 * 
 * \return true if there is a cyclic path from <B>node</B> to itself, false otherwise.
*/
template <typename Graph>
bool is_cyclical(const Graph& g, const typename Graph::node_type& node)
{ 
 //Utilize a BFS to see if we can get from node back to node
 using node_type = typename Graph::node_type;
 using adj_iter = typename Graph::const_adjacency_iterator;
 
 std::queue<node_type> to_examine;
 std::set<node_type> examined_nodes;
 
 to_examine.push(node);
 while(!to_examine.empty()) {
 node_type current_node = to_examine.front();
 to_examine.pop();
 auto adj_nodes = g.adjacent_nodes(current_node);
 for(auto it = adj_nodes.first; it != adj_nodes.second; ++it) {
 if(examined_nodes.find(*it) == examined_nodes.end()) {
 if(*it == node) {
 return true;
 }
 to_examine.push(*it);
 examined_nodes.insert(*it);
 }
 }
 }
 return false;
}
/*! \brief Finds all nodes reachable from a given node. Equivalent to running a depth
 * or bredth-first search on that node. 
 * 
 * \param g A graph to search over.
 * \param node The node from which to begin the search.
 * 
 * \return A std::set containing all the nodes reachable from <B>node</B>.
*/
template <typename Graph>
std::set<typename Graph::node_type> 
connected_component(const Graph& g, const typename Graph::node_type& node)
{
 using node_type = typename Graph::node_type;
 std::set<node_type> connected;
 std::insert_iterator<std::set<node_type>> ins_it(connected, connected.begin());
 depth_first_search(g, node, ins_it);
 return connected;
}
/*! \brief Finds all connected components of a given graph.
 * 
 * Connected components partition the graph into equivalence classes based on
 * reachability. That is, any node in a given connected component is reachable
 * by any other node in the same connected component, and any node not in that same
 * connected component is not reachable. 
 * 
 * \param g A graph to search over.
 * 
 * \return A std::set of std::sets, each consisting of one connected component.
*/
template <typename Graph>
std::set<std::set<typename Graph::node_type>> 
all_connected_components(const Graph& g)
{
 using node_type = typename Graph::node_type;
 std::set<std::set<node_type>> cc;
 bool found = false;
 
 for(auto it = g.begin(); it != g.end(); ++it) {
 for(auto cc_subset = cc.begin(); cc_subset != cc.end(); ++cc_subset) {
 if(cc_subset->find(it->first) != cc_subset->end()) {
 found = true;
 break;
 }
 }
 if(!found) {
 cc.insert(connected_component(g,it->first));
 }
 found = false;
 }
 return cc;
}
/*! \brief Determines if the graph is fully connected.
 * 
 * A fully connected graph is one in which there is a path from any node
 * to any other node.
 * 
 * \param g A graph to search over.
 * 
 * \return true if the graph is full connected, false otherwise.
*/
template <typename Graph>
bool is_fully_connected(const Graph& g)
{
 auto s = all_connected_components(g);
 return s.size() == 1;
}
} //end namespace graph
} //end namespace simplegl
#endif //GRAPH_SEARCH_SGL_HPP_
/*! @} End of Doxygen Group graph_algorithm */

topological_sort.hpp

#ifndef TOPOLOGICAL_SORT_SGL_HPP_
#define TOPOLOGICAL_SORT_SGL_HPP_
#include <deque>
#include <iostream>
#include "graph/graph_traits.hpp"
namespace simplegl
{
namespace graph
{
// Returns true iff the given graph can be topologically sorted,
// false otherwise.
template <typename Graph>
bool is_topologically_sortable(const Graph& g)
{
 using node_type = typename Graph::node_type;
 if(!is_directed<Graph>::value) { return false; }
 Graph possible_dag(g); 
 std::deque<node_type> zero_degree;
 for(auto it = possible_dag.begin(); it != possible_dag.end(); ++it) {
 if(possible_dag.indegree(it->first) == 0) {
 zero_degree.push_back(it->first);
 }
 }
 
 while(!zero_degree.empty()) {
 node_type& w = zero_degree.front();
 auto adjacent = possible_dag.adjacent_nodes(w);
 for(auto it = adjacent.first; it != adjacent.second; ++it) {
 possible_dag.remove_edge(w, *it);
 if(possible_dag.indegree(*it) == 0) {
 zero_degree.push_back(*it);
 }
 }
 zero_degree.pop_front();
 }
 return possible_dag.edge_size() == 0;
}
// Topologically sorts the given graph, if possible.
// Returns a std::deque containing the topological sorting, if 
// it exists, or an empty deque otherwise.
template <typename Graph>
std::deque<typename Graph::node_type> topologically_sort(const Graph& g)
{
 using node_type = typename Graph::node_type;
 if(!is_directed<Graph>::value) { return std::deque<node_type>(); }
 Graph possible_dag(g); 
 std::deque<node_type> zero_degree;
 std::deque<node_type> sorted;
 for(auto it = possible_dag.begin(); it != possible_dag.end(); ++it) {
 if(possible_dag.indegree(it->first) == 0) {
 zero_degree.push_back(it->first);
 }
 }
 
 while(!zero_degree.empty()) {
 node_type& w = zero_degree.front();
 sorted.push_back(w);
 auto adjacent = possible_dag.adjacent_nodes(w);
 for(auto it = adjacent.first; it != adjacent.second; ++it) {
 possible_dag.remove_edge(w, *it);
 if(possible_dag.indegree(*it) == 0) {
 zero_degree.push_back(*it);
 }
 }
 zero_degree.pop_front();
 }
 if(possible_dag.edge_size() == 0) {
 return sorted;
 }
 return std::deque<node_type>();
}
} // end namespace graph
} // end namespace simplegl
#endif // TOPOLOGICAL_SORT_SGL_HPP_
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /