add utilities to graph API

This commit is contained in:
Laurent Perron
2016-09-12 13:41:45 +02:00
parent 5224f26bbb
commit 1e00bb3da1
3 changed files with 80 additions and 17 deletions

View File

@@ -1029,8 +1029,14 @@ void BaseGraph<NodeIndexType, ArcIndexType, HasReverseArcs>::
t##ArcIterator(*this, node, e)); \
}
// Adapt our old iteration style to support range-based for loops.
// Adapt our old iteration style to support range-based for loops. Add typedefs
// required by std::iterator_traits.
#define DEFINE_STL_ITERATOR_FUNCTIONS(iterator_class_name) \
using iterator_category = std::input_iterator_tag; \
using difference_type = ptrdiff_t; \
using pointer = const ArcIndexType*; \
using reference = const ArcIndexType&; \
using value_type = ArcIndexType; \
bool operator!=(const iterator_class_name& other) const { \
return index_ != other.index_; \
} \
@@ -1152,6 +1158,12 @@ class ListGraph<NodeIndexType, ArcIndexType>::OutgoingArcIterator {
template <typename NodeIndexType, typename ArcIndexType>
class ListGraph<NodeIndexType, ArcIndexType>::OutgoingHeadIterator {
public:
using iterator_category = std::input_iterator_tag;
using difference_type = ptrdiff_t;
using pointer = const NodeIndexType*;
using reference = const NodeIndexType&;
using value_type = NodeIndexType;
OutgoingHeadIterator(const ListGraph& graph, NodeIndexType node)
: graph_(graph), index_(graph.start_[node]) {
DCHECK(graph.IsNodeValid(node));
@@ -1583,13 +1595,8 @@ class ReverseArcListGraph<NodeIndexType, ArcIndexType>::OutgoingHeadIterator {
DCHECK(Ok());
index_ = graph_->next_[index_];
}
bool operator!=(
const typename ReverseArcListGraph<
NodeIndexType, ArcIndexType>::OutgoingHeadIterator& other) const {
return index_ != other.index_;
}
ArcIndexType operator*() const { return Index(); }
void operator++() { Next(); }
DEFINE_STL_ITERATOR_FUNCTIONS(OutgoingHeadIterator);
private:
const ReverseArcListGraph* graph_;
@@ -2156,6 +2163,23 @@ class CompleteBipartiteGraph
ArcIndexType from) const;
IntegerRange<NodeIndexType> operator[](NodeIndexType node) const;
// Deprecated interface.
class OutgoingArcIterator {
public:
OutgoingArcIterator(const CompleteBipartiteGraph& graph, NodeIndexType node)
: index_(graph.right_nodes_ * node),
limit_(node >= graph.left_nodes_ ? index_
: graph.right_nodes_ * (node + 1)) {}
bool Ok() const { return index_ < limit_; }
ArcIndexType Index() const { return index_; }
void Next() { index_++; }
private:
ArcIndexType index_;
const ArcIndexType limit_;
};
private:
const NodeIndexType left_nodes_;
const NodeIndexType right_nodes_;
@@ -2165,7 +2189,7 @@ template <typename NodeIndexType, typename ArcIndexType>
NodeIndexType CompleteBipartiteGraph<NodeIndexType, ArcIndexType>::Head(
ArcIndexType arc) const {
DCHECK(this->IsArcValid(arc));
return arc % right_nodes_;
return left_nodes_ + arc % right_nodes_;
}
template <typename NodeIndexType, typename ArcIndexType>
@@ -2207,7 +2231,7 @@ template <typename NodeIndexType, typename ArcIndexType>
IntegerRange<NodeIndexType> CompleteBipartiteGraph<
NodeIndexType, ArcIndexType>::operator[](NodeIndexType node) const {
if (node < left_nodes_) {
return IntegerRange<NodeIndexType>(0, right_nodes_);
return IntegerRange<NodeIndexType>(left_nodes_, left_nodes_ + right_nodes_);
} else {
return IntegerRange<NodeIndexType>(0, 0);
}

View File

@@ -27,15 +27,14 @@
// anywhere, but you have to return to your start location.
//
// By complete we mean that the algorithm guarantees to compute the optimal
// solution.
// The algorithm uses dynamic programming. Its time complexity is
// O(n * 2 ^ (n - 1)), where n is the number of nodes to be visited, and '^'
// denotes exponentiation. Its space complexity is also O(n * 2 ^ (n - 1)).
// solution. The algorithm uses dynamic programming. Its time complexity is
// O(n^2 * 2^(n-1)), where n is the number of nodes to be visited, and '^'
// denotes exponentiation. Its space complexity is O(n * 2 ^ (n - 1)).
//
// Note that the naive implementation of the SHPP
// exploring all permutations without memorizing intermediate results would
// have a complexity of (n - 1)! (factorial of (n - 1) ), which is much higher
// than n * 2 ^ (n - 1). To convince oneself of this, just use Stirling's
// than n^2 * 2^(n-1). To convince oneself of this, just use Stirling's
// formula: n! ~ sqrt(2 * pi * n)*( n / exp(1)) ^ n.
// Because of these complexity figures, the algorithm is not practical for
// problems with more than 20 nodes.

View File

@@ -22,6 +22,7 @@
#include <string>
#include "base/numbers.h"
#include "base/hash.h"
#include "base/split.h"
#include "base/join.h"
#include "base/murmur.h"
@@ -34,8 +35,7 @@ namespace operations_research {
// Diagnoses whether a graph is symmetric. A graph is symmetric iff
// for all (a, b), the number of arcs a->b is equal to the number of arcs b->a.
// If it returns "false", the graph is certainly not symmetric; if it returns
// "true" then the graph is most likely symmetric. It works in O(graph size).
// Works in O(graph size).
template <class Graph>
bool GraphIsSymmetric(const Graph& graph);
@@ -47,6 +47,16 @@ template <class Graph>
util::StatusOr<Graph*> RemapGraph(const Graph& graph,
const std::vector<int>& new_node_index);
// Returns a std::string representation of a graph: one arc per line. Eg.:
// "1->2\n3->3" for a graph with 4 nodes and 2 arcs (1->2) and (3->3).
// Arcs are sorted by their tail, then by the order of OutgoingArcs().
template <class Graph>
std::string GraphToString(const Graph& graph);
// Returns a copy of "graph", without self-arcs and duplicate arcs.
template <class Graph>
std::unique_ptr<Graph> RemoveSelfArcsAndDuplicateArcs(const Graph& graph);
// Read a graph file in the simple ".g" format: the file should be a text file
// containing only space-separated integers, whose first line is:
// <num nodes> <num edges> [<num_colors> <index of first node with color #1>
@@ -166,6 +176,36 @@ util::StatusOr<Graph*> RemapGraph(const Graph& old_graph,
return new_graph.release();
}
template <class Graph>
std::string GraphToString(const Graph& graph) {
std::string out;
for (const typename Graph::NodeIndex node : graph.AllNodes()) {
for (const typename Graph::ArcIndex arc : graph.OutgoingArcs(node)) {
if (!out.empty()) out += '\n';
StrAppend(&out, node, "->", graph.Head(arc));
}
}
return out;
}
template <class Graph>
std::unique_ptr<Graph> RemoveSelfArcsAndDuplicateArcs(const Graph& graph) {
std::unique_ptr<Graph> g(new Graph(graph.num_nodes(), graph.num_arcs()));
typedef typename Graph::ArcIndex ArcIndex;
typedef typename Graph::NodeIndex NodeIndex;
hash_set<std::pair<NodeIndex, NodeIndex>> arcs;
for (const NodeIndex tail : graph.AllNodes()) {
for (const ArcIndex arc : graph.OutgoingArcs(tail)) {
const NodeIndex head = graph.Head(arc);
if (head != tail && arcs.insert({tail, head}).second) {
g->AddArc(tail, head);
}
}
}
g->Build();
return g;
}
template <class Graph>
util::StatusOr<Graph*> ReadGraphFile(
const std::string& filename, bool directed,