From 71b302bc498e0332aa1b551abf48c52c027b9667 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 27 Oct 2004 14:38:15 +0000 Subject: [PATCH] Merge from graph_devel_1_33_0 branch [SVN r25893] --- doc/AStarHeuristic.html | 142 ++++++ doc/AStarVisitor.html | 217 ++++++++ doc/astar_heuristic.html | 100 ++++ doc/astar_search.html | 477 ++++++++++++++++++ doc/astar_visitor.html | 112 ++++ doc/bibliography.html | 7 +- doc/floyd_warshall_shortest.html | 160 ++++++ doc/fruchterman_reingold.html | 206 ++++++++ doc/johnson_all_pairs_shortest.html | 4 +- doc/random_layout.html | 94 ++++ doc/table_of_contents.html | 6 + doc/visitor_concepts.html | 1 + example/astar-cities.cpp | 224 ++++++++ example/test-astar-cities.dot | 36 ++ include/boost/graph/astar_search.hpp | 390 ++++++++++++++ .../graph/bellman_ford_shortest_paths.hpp | 6 +- .../boost/graph/floyd_warshall_shortest.hpp | 240 +++++++++ include/boost/graph/fruchterman_reingold.hpp | 378 ++++++++++++++ include/boost/graph/named_function_params.hpp | 76 +++ include/boost/graph/random_layout.hpp | 49 ++ include/boost/graph/relax.hpp | 35 +- include/boost/graph/simple_point.hpp | 15 + test/Jamfile | 3 + test/astar_search_test.cpp | 213 ++++++++ test/floyd_warshall_test.cpp | 394 +++++++++++++++ test/layout_test.cpp | 113 ++++- 26 files changed, 3684 insertions(+), 14 deletions(-) create mode 100644 doc/AStarHeuristic.html create mode 100644 doc/AStarVisitor.html create mode 100644 doc/astar_heuristic.html create mode 100644 doc/astar_search.html create mode 100644 doc/astar_visitor.html create mode 100644 doc/floyd_warshall_shortest.html create mode 100644 doc/fruchterman_reingold.html create mode 100644 doc/random_layout.html create mode 100644 example/astar-cities.cpp create mode 100644 example/test-astar-cities.dot create mode 100644 include/boost/graph/astar_search.hpp create mode 100644 include/boost/graph/floyd_warshall_shortest.hpp create mode 100644 include/boost/graph/fruchterman_reingold.hpp create mode 100644 include/boost/graph/random_layout.hpp create mode 100644 include/boost/graph/simple_point.hpp create mode 100644 test/astar_search_test.cpp create mode 100644 test/floyd_warshall_test.cpp diff --git a/doc/AStarHeuristic.html b/doc/AStarHeuristic.html new file mode 100644 index 00000000..7ad10b6d --- /dev/null +++ b/doc/AStarHeuristic.html @@ -0,0 +1,142 @@ + + + +Boost Graph Library: AStarHeuristic + +C++ Boost + +
+ +

AStar Heuristic Concept

+ +This concept defines the interface for the heuristic function of an A* +search, which is responsible for estimating the remaining cost from +some vertex to a goal. The user can create a class that matches this +interface, and then pass objects of the class into astar_search() to guide the +order of vertex examination of the search. The heuristic instance +must incorporate any necessary information about goal vertices in the +graph. + +For further discussion of the use of heuristics in an A* search, see +the documentation of astar_search(). + +

Refinement of

+ +Unary +Function (must take a single argument -- a graph vertex -- and +return a cost value) and Copy Constructible +(copying a heuristic should be a lightweight operation). + + +

Notation

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HA type that is a model of AStar Heuristic.
hAn object of type H.
GA type that is a model of Graph.
gAn object of type G.
uAn object of type boost::graph_traits<G>::vertex_descriptor.
CostTypeA type that can be used with the compare and +combine functions passed to A*.
cAn object of type CostType.
+ +

Associated Types

+ +none +

+ +

Valid Expressions

+ + + + + + + + + + + + + +
NameExpressionReturn TypeDescription
Call HeuristicCostType c = h(u)CostType +Called for the target of every out edge of a vertex being examined. +
+ +

Models

+ + + +

Concept Checking Class

+ +
+  template <class Heuristic, class Graph>
+  struct AStarHeuristicConcept {
+    void constraints()
+    {
+      function_requires< CopyConstructibleConcept<Heuristic> >();
+      h(u);
+    }
+    Heuristic h;
+    typename graph_traits<Graph>::vertex_descriptor u;
+  };
+
+ +
+
+ + +
Copyright © 2004 +Kristopher Beevers, +Rensselaer Polytechnic Institute (beevek@cs.rpi.edu) +
+ + + diff --git a/doc/AStarVisitor.html b/doc/AStarVisitor.html new file mode 100644 index 00000000..44c0c839 --- /dev/null +++ b/doc/AStarVisitor.html @@ -0,0 +1,217 @@ + + + +Boost Graph Library: AStarVisitor + +C++ Boost + +
+ +

AStar Visitor Concept

+ +This concept defines the visitor interface for astar_search(). Users can +define a class with the AStar Visitor interface and pass an object of +the class to astar_search(), thereby augmenting the actions +taken during the graph search. + +

Refinement of

+ +Copy Constructible +(copying a visitor should be a lightweight operation). + + +

Notation

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
VA type that is a model of AStar Visitor.
visAn object of type V.
GA type that is a model of Graph.
gAn object of type G.
eAn object of type boost::graph_traits<G>::edge_descriptor.
s,u,vAn object of type boost::graph_traits<G>::vertex_descriptor.
dAn object of type DistanceMap.
WeightMapA type that is a model of Readable Property +Map.
wAn object of type WeightMap.
+ +

Associated Types

+ +none +

+ +

Valid Expressions

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameExpressionReturn TypeDescription
Initialize Vertexvis.initialize_vertex(u, g)void +This is invoked on each vertex of the graph when it is first +initialized (i.e., when its property maps are initialized). +
Discover Vertexvis.discover_vertex(u, g)void +This is invoked when a vertex is first discovered and is added to the +OPEN list. +
Examine Vertexvis.examine_vertex(u, g)void +This is invoked on a vertex as it is popped from the queue (i.e. it +has the lowest cost on the OPEN list). This happens immediately before +examine_edge() is invoked on each of the out-edges of vertex +u. +
Examine Edgevis.examine_edge(e, g)void +This is invoked on every out-edge of each vertex after it is +examined. +
Edge Relaxedvis.edge_relaxed(e, g)void +Upon examination, if the following condition holds then the edge is +relaxed (the distance of its target vertex is reduced) and this method +is invoked: +
+
+tie(u, s) = incident(e, g);
+D d_u = get(d, u), d_v = get(d, s);
+W w_e = get(w, e);
+assert(compare(combine(d_u, w_e), d_s));
+
+
+
Edge Not Relaxedvis.edge_not_relaxed(e, g)void +Upon examination, if an edge is not relaxed (see above), then this +method is invoked. +
Black Targetvis.black_target(e, g)void +This is invoked when a vertex that is on the CLOSED list is +``rediscovered'' via a more efficient path, and is re-added to the +OPEN list. +
Finish Vertexvis.finish_vertex(u, g)void +This is invoked on a vertex when it is added to the CLOSED list, which +happens after all of its out edges have been examined. +
+ +

Models

+ + + + +

See also

+ +Visitor concepts + +
+
+ + +
Copyright © 2004 +Kristopher Beevers, +Rensselaer Polytechnic Institute (beevek@cs.rpi.edu) +
+ + + diff --git a/doc/astar_heuristic.html b/doc/astar_heuristic.html new file mode 100644 index 00000000..652e7056 --- /dev/null +++ b/doc/astar_heuristic.html @@ -0,0 +1,100 @@ + + + +Boost Graph Library: astar_heuristic + +C++ Boost + +
+ +

+
+astar_heuristic<Graph, CostType>
+
+

+ +This class is a default implementation of the AStarHeuristic concept. It +implements a "zero" heuristic -- a heuristic function that returns a +cost of zero regardless of the vertex it is passed. + +

Model of

+ +AStarHeuristic + +

Template Parameters

+ +

+ + + + + + + + + + + + + + + +
ParameterDescriptionDefault
Graph +The type of the graph being searched. +
CostType +A type that can be used with the compare and +combine functions passed to A*. Typically an integer or +floating point type. +
+ +

Where Defined

+ +

+ +boost/graph/astar_search.hpp + +

Member Functions

+ +This class implements the single member function required by AStarHeuristic: + + + + + + + + +
FunctionDescription
+CostType operator()(graph_traits<Graph>::vertex_descriptor u); + +Called for the target of every out edge of a vertex being examined. +Returns the cost, estimated by the heuristic, from vertex u +to a goal. +
+ +
+
+ + +
Copyright © 2004 +Kristopher Beevers, +Rensselaer Polytechnic Institute (beevek@cs.rpi.edu) +
+ + + diff --git a/doc/astar_search.html b/doc/astar_search.html new file mode 100644 index 00000000..4927b85a --- /dev/null +++ b/doc/astar_search.html @@ -0,0 +1,477 @@ + + + +Boost Graph Library: A* Heuristic Search + +C++ Boost + +
+ +

+astar_search +

+ + +

+

+// Named parameter interface
+template <typename VertexListGraph,
+          typename AStarHeuristic,
+          typename P, typename T, typename R>
+void
+astar_search
+  (VertexListGraph &g,
+   typename graph_traits<VertexListGraph>::vertex_descriptor s,
+   AStarHeuristic h, const bgl_named_params<P, T, R>& params);
+
+// Non-named parameter interface
+template <typename VertexListGraph, typename AStarHeuristic,
+          typename AStarVisitor, typename PredecessorMap,
+          typename CostMap, typename DistanceMap,
+          typename WeightMap, typename VertexIndexMap,
+	  typename ColorMap,
+          typename CompareFunction, typename CombineFunction,
+          typename CostInf, typename CostZero>
+inline void
+astar_search
+  (VertexListGraph &g,
+   typename graph_traits<VertexListGraph>::vertex_descriptor s,
+   AStarHeuristic h, AStarVisitor vis,
+   PredecessorMap predecessor, CostMap cost,
+   DistanceMap distance, WeightMap weight,
+   VertexIndexMap index_map, ColorMap color,
+   CompareFunction compare, CombineFunction combine,
+   CostInf inf, CostZero zero);
+
+ +

+This algorithm implements a heuristic search on a weighted, directed +or undirected graph for the case where all edge weights are +non-negative. +

+ +

+The A* algorithm is a heuristic graph search algorithm: an A* +search is "guided" by a heuristic function. A heuristic +function h(v) is one which estimates the cost from a non-goal +state (v) in the graph to some goal state, g. +Intuitively, A* follows paths (through the graph) to the goal that are +estimated by the heuristic function to be the best paths. Unlike +best-first search, A* takes into account the known cost from the start +of the search to v; the paths A* takes are guided by a function +f(v) = g(v) + h(v), where h(v) is the heuristic +function, and g(v) (sometimes denoted c(s, v)) is the +known cost from the start to v. Clearly, the efficiency of A* +is highly dependent on the heuristic function with which it is used. +

+ +

+The A* algorithm is very similar to Dijkstra's Shortest Paths +algorithm. This implementation finds all the shortest paths from the +start vertex to every other vertex by creating a search tree, +examining vertices according to their remaining cost to some goal, as +estimated by a heuristic function. Most commonly, A* is used to find +some specific goal vertex or vertices in a graph, after which the +search is terminated. +

+ +

+A* is particularly useful for searching implicit graphs. +Implicit graphs are graphs that are not completely known at the +beginning of the search. Upon visiting a vertex, its neighbors are +"generated" and added to the search. Implicit graphs are particularly +useful for searching large state spaces -- in gameplaying scenarios +(e.g. chess), for example -- in which it may not be possible to store +the entire graph. Implicit searches can be performed with this +implementation of A* by creating special visitors that generate +neighbors of newly-expanded vertices. +

+ +

+This implementation of A* is based on an OPEN/CLOSED list formulation +of the algorithm. Vertices on the OPEN list have been ``discovered'' +by the algorithm, but not ``expanded'' (we have not discovered their +adjacent vertices). Vertices on the CLOSED list have been completely +examined by our search (we have expanded them and added their children +to the OPEN list). Vertices that are on neither list have not been +encountered in any context so far in our search. A major advantage of +this formulation of the A* algorithm over other approaches is that it +avoids ``cycles'' in the state space; the search will not become +trapped by loops in the graph. The OPEN/CLOSED lists are implemented +using BGL's vertex coloring mechanisms. Vertices in OPEN are colored +gray, vertices in CLOSED are colored black, and undiscovered vertices +are colored white. +

+ +

+The criteria for expanding a vertex on the OPEN list is that it has +the lowest f(v) = g(v) + h(v) value of all vertices on OPEN. +Cost information about vertices is stored in a property map. +

+ +

+The following is the pseudocode for the A* heuristic search algorithm. +In the pseudocode, h is the heuristic function, w is the +edge weight, d is the distance of a vertex from s, and +Q is a priority queue, sorted by f, the estimated cost +to the goal of the path through a vertex. p is a predecessor +map. The visitor event points for the algorithm are indicated by the +labels on the right. +

+ + + + + + +
+
+A*(G, s, h)
+  for each vertex u in V
+    d[u] := f[u] := infinity
+    color[u] := WHITE
+    p[u] := u
+  end for
+  color[s] := GRAY
+  d[s] := 0
+  f[s] := h(s)
+  INSERT(Q, s)
+  while (Q != Ø)
+    u := EXTRACT-MIN(Q)
+    for each vertex v in Adj[u]
+      if (w(u,v) + d[u] < d[v])
+        d[v] := w(u,v) + d[u]
+	f[v] := d[v] + h(v)
+	p[v] := u
+	if (color[v] = WHITE)
+	  color[v] := GRAY
+	  INSERT(Q, v)
+	else if (color[v] = BLACK)
+	  color[v] := GRAY
+	  INSERT(Q, v)
+	end if
+      else
+        ...
+    end for
+    color[u] := BLACK
+  end while
+
+
+
+
+initialize vertex u
+
+
+
+
+
+
+
+discover vertex s
+
+examine vertex u
+examine edge (u,v)
+
+edge (u,v) relaxed
+
+
+
+
+discover vertex v
+
+
+reopen vertex v
+
+
+edge (u,v) not relaxed
+
+finish vertex u
+
+
+ +

Where Defined

+ +boost/graph/astar_search.hpp + +

Parameters

+ +IN: VertexListGraph& g +
+ The graph object on which the algorithm will be applied. The type + VertexListGraph must be a model of the + Vertex List Graph concept. +
+ +IN: vertex_descriptor s +
+ The start vertex for the search. All distances will be calculated + from this vertex, and the shortest paths tree (recorded in the + predecessor map) will be rooted at this vertex. +
+ +IN: AStarHeuristic h +
+ The heuristic function that guides the search. The type + AStarHeuristic must be a model of the AStarHeuristic + concept. +
+ +

Named Parameters

+ +IN: weight_map(WeightMap w_map) +
+ The weight or ``length'' of each edge in the graph. The weights + must all be non-negative; the algorithm will throw a negative_edge + exception if one of the edges is negative. The type + WeightMap must be a model of Readable + Property Map. The edge descriptor type of the graph needs + to be usable as the key type for the weight map. The value type + for this map must be the same as the value type of the distance + map.
+ Default: get(edge\_weight, g) +
+ +IN: vertex_index_map(VertexIndexMap i_map) +
+ This maps each vertex to an integer in the range [0, + num_vertices(g)). This is necessary for efficient updates of + the heap data structure when an edge is relaxed. The type + VertexIndexMap must be a model of Readable + Property Map. The value type of the map must be an integer + type. The vertex descriptor type of the graph needs to be usable as + the key type of the map.
+ + Default: get(vertex_index, g) +
+ +OUT: predecessor_map(PredecessorMap p_map) +
+ + The predecessor map records the edges in the minimum spanning tree. + Upon completion of the algorithm, the edges (p[u],u) for + all u in V are in the minimum spanning tree. If + p[u] = u then u is either the start vertex or a + vertex that is not reachable from the start. The + PredecessorMap type must be a Read/Write + Property Map with key and vertex types the same as the + vertex descriptor type of the graph.
+ + Default: dummy_property_map +
+ +UTIL/OUT: distance_map(DistanceMap d_map) +
+ + The shortest path weight from the start vertex s to each + vertex in the graph g is recorded in this property map. + The shortest path weight is the sum of the edge weights along the + shortest path. The type DistanceMap must be a model of Read/Write + Property Map. The vertex descriptor type of the graph + needs to be usable as the key type of the distance map. The value + type of the distance map is the element type of a Monoid formed with the + combine function object and the zero object for the + identity element. Also the distance value type must have a StrictWeakOrdering + provided by the compare function object.
+ + Default: iterator_property_map created from a + std::vector with the same value type as the + WeightMap, and of size num_vertices(g), and using + the i_map for the index map. +
+ +UTIL/OUT: rank_map(CostMap c_map) +
+ + The f-value for each vertex. The f-value is defined + as the sum of the cost to get to a vertex from the start vertex, and + the estimated cost (as returned by the heuristic function + h) from the vertex to a goal. The type CostMap + must be a model of Read/Write + Property Map. The vertex descriptor type of the graph + needs to be usable as the key type of the distance map. The value + type of the distance map is the element type of a Monoid formed with the + combine function object and the zero object for the + identity element. Also the distance value type must have a StrictWeakOrdering + provided by the compare function object. The value type + for this map must be the same as the value type for the distance + map.
+ + Default: iterator_property_map created from a + std::vector with the same value type as the + WeightMap, and of size num_vertices(g), and using + the i_map for the index map. +
+ +UTIL/OUT: color_map(ColorMap c_map) +
+ + This is used during the execution of the algorithm to mark the + vertices, indicating whether they are on the OPEN or CLOSED lists. + The vertices start out white and become gray when they are inserted + into the OPEN list. They then turn black when they are examined and + placed on the CLOSED list. At the end of the algorithm, vertices + reachable from the source vertex will have been colored black. All + other vertices will still be white. The type ColorMap must + be a model of Read/Write + Property Map. A vertex descriptor must be usable as the + key type of the map, and the value type of the map must be a model + of Color Value.
+ + Default: iterator_property_map created from a + std::vector of value type default_color_type, with + size num_vertices(g), and using the i_map for the + index map. +
+ +IN: distance_compare(CompareFunction cmp) +
+ + This function is use to compare distances to determine which vertex + is closer to the start vertex, and to compare f-values to + determine which vertex on the OPEN list to examine next. The + CompareFunction type must be a model of Binary + Predicate and have argument types that match the value type + of the DistanceMap property map.
+ + Default: std::less<D> with D = typename + property_traits<DistanceMap>::value_type. +
+ +IN: distance_combine(CombineFunction cmb) +
+ + This function is used to combine distances to compute the distance + of a path, and to combine distance and heuristic values to compute + the f-value of a vertex. The CombineFunction type + must be a model of Binary + Function. Both argument types of the binary function must + match the value type of the DistanceMap property map (which + is the same as that of the WeightMap and CostMap + property maps). The result type must be the same type as the + distance value type.
+ + Default: std::plus<D> with D = typename + property_traits<DistanceMap>::value_type. +
+ +IN: distance_inf(D inf) +
+ + The inf object must be the greatest value of any D + object. That is, compare(d, inf) == true for any d != + inf. The type D is the value type of the + DistanceMap.
+ + Default: std::numeric_limits<D>::max() +
+ +IN: distance_zero(D zero) +
+ + The zero value must be the identity element for the Monoid formed by the distance + values and the combine function object. The type + D is the value type of the DistanceMap.
+ + Default: D() with D = typename + property_traits<DistanceMap>::value_type. +
+ +OUT: visitor(AStarVisitor v) +
+ + Use this to specify actions that you would like to happen during + certain event points within the algorithm. The type + AStarVisitor must be a model of the AStarVisitor concept. The + visitor object is passed by value [1].
+ + Default: astar_visitor<null_visitor> +
+ +

Complexity

+ +

+The time complexity is O((E + V) log V). + +

Visitor Event Points

+ + + +

Example

+ +

+See +example/astar-cities.cpp for an example of +using A* search. + +

Notes

+ +[1] Since the visitor parameter is passed by value, if +your visitor contains state then any changes to the state during the +algorithm will be made to a copy of the visitor object, not the +visitor object passed in. Therefore you may want the visitor to hold +this state by pointer or reference. + +
+
+ + +
Copyright © 2004 +Kristopher Beevers, +Rensselaer Polytechnic Institute (beevek@cs.rpi.edu) +
+ + + diff --git a/doc/astar_visitor.html b/doc/astar_visitor.html new file mode 100644 index 00000000..59b26d4a --- /dev/null +++ b/doc/astar_visitor.html @@ -0,0 +1,112 @@ + + + +Boost Graph Library: astar_visitor + +C++ Boost + +
+ +

+
+astar_visitor<EventVisitorList>
+
+

+ +This class is an adapter that converts a list of EventVisitor's (constructed using +std::pair) into a AStarVisitor. + + +

Example

+ +See the example for EventVisitor. + +

Model of

+ +AStarVisitor + +

Template Parameters

+ +

+ + + + + + + + + + +
ParameterDescriptionDefault
EventVisitorList +A list of EventVisitor's created +with std::pair. +null_visitor
+ +

Where Defined

+ +

+ +boost/graph/astar_search.hpp + +

Member Functions

+ +This class implements all of the member functions required by AStarVisitor. In each function the +appropriate event is dispatched to the EventVisitor's in the +EventVisitorList. + +

Non-Member Functions

+ + + + + + + + +
FunctionDescription
+template <class EventVisitorList>
+astar_visitor<EventVisitorList>
+make_astar_visitor(EventVisitorList ev_list); +
+Returns the event visitor list adapted to be an A* visitor. +
+ +

See Also

+ +Visitor concepts +

+The following are event visitors: predecessor_recorder, +distance_recorder, +time_stamper, +and property_writer. + +
+


+ + +
Copyright © 2004 +Kristopher Beevers, +Rensselaer Polytechnic Institute (beevek@cs.rpi.edu) +
+ + + diff --git a/doc/bibliography.html b/doc/bibliography.html index 8b633001..6c5763c1 100644 --- a/doc/bibliography.html +++ b/doc/bibliography.html @@ -352,7 +352,12 @@ Technical Report BN9/71, Stichting Mahtematisch Centrum, Amsterdam, 1971.
T. Kamada and S. Kawai
An algorithm for drawing general undirected graphs.
Information Processing Letters, 31, pp. 7-15, 1989. - + +

58 +
T. Fruchterman and E. Reingold
+ Graph drawing by force-directed placement.
+Software--Practice & Experience, 21 (11), pp. 1129-1164, 1991. +

diff --git a/doc/floyd_warshall_shortest.html b/doc/floyd_warshall_shortest.html new file mode 100644 index 00000000..84856ecb --- /dev/null +++ b/doc/floyd_warshall_shortest.html @@ -0,0 +1,160 @@ + + +Johnson All Pairs Shortest Paths + +C++ Boost + +
+ +

+floyd_warshall_all_pairs_shortest_paths +

+ +
// Named parameters version
+template <class VertexListGraph, class DistanceMatrix,
+    class P, class T, class R>
+bool floyd_warshall_initialized_all_pairs_shortest_paths(
+    const VertexListGraph& g, DistanceMatrix& d,
+    const bgl_named_params<P, T, R>& params)
+
+template <class VertexAndEdgeListGraph, class DistanceMatrix,
+    class P, class T, class R>
+bool floyd_warshall_all_pairs_shortest_paths(
+    const VertexAndEdgeListGraph& g, DistanceMatrix& d,
+    const bgl_named_params<P, T, R>& params)
+
+// Positional parameter versions
+\begin{verbatim}
+template <typename VertexListGraph, typename DistanceMatrix,
+    typename BinaryPredicate, typename BinaryFunction,
+    typename Infinity, typename Zero>
+bool floyd_warshall_initialized_all_pairs_shortest_paths(
+    const VertexListGraph& g, DistanceMatrix& d,
+    const BinaryPredicate& compare, const BinaryFunction& combine,
+    const Infinity& inf, const Zero& zero)
+
+template <typename VertexAndEdgeListGraph, typename DistanceMatrix,
+    typename WeightMap, typename BinaryPredicate,
+    typename BinaryFunction, typename Infinity, typename Zero>
+bool floyd_warshall_all_pairs_shortest_paths(
+    const VertexAndEdgeListGraph& g, DistanceMatrix& d,
+    const WeightMap& w, const BinaryPredicate& compare,
+    const BinaryFunction& combine,
+    const Infinity& inf, const Zero& zero)
+ +

+These algorithms find the shortest distance between every pair of +vertices in the graph. The algorithms return false if there is a +negative weight cycle in the graph, true otherwise. The shortest +distance between each pair of vertices is stored in the distance +matrix d. The difference between the two algorithms is in +whether the distance matrix is assumed to be initialized or not, as +discussed below under the OUT parameter description. + +

This algorithm should be used to compute shortest paths between +every pair of vertices for dense graphs. For sparse graphs, use johnson_all_pairs_shortest_paths. + +

Where Defined

+ +

+boost/graph/floyd_warshall_shortest.hpp + +

Parameters

+IN: Graph& g +
+A directed or undirected graph. The graph must be a model of Vertex List Graph for calls to +floyd_warshall_initialized_all_pairs_shortest_paths, and +Vertex And Edge List Graph for calls to +floyd_warshall_all_pairs_shortest_paths.
+
+ +OUT: DistanceMatrix& d +
+The length of the shortest path between each pair of vertices +u,v are +stored in the matrix at location D[u][v]. The +DistanceMatrix must be +of type {M, I, V} where I is of type +vertex_descriptor and V is the +type of the weight_map. The set of types must be a model of +BasicMatrix, with the exceptions that +it isn't required to +run in constant time, and it must be mutable. The matrix must be +properly initialized when it is passed to the function +floyd_warshall_initialized_all_pairs_shortest_paths. If the +function floyd_warshall_all_pairs_shortest_paths is used then the +matrix will be initialized for the user. +
+ +

Named Parameters

+ +IN: weight_map(WeightMap w) +
+The weight of length of each edge in the graph. The WeightMap +must be a model of Readable Property +Map. The edge descriptor +type of the graph needs to be usable as the key type for the weight +map. The value_type of the weight map must be the type of the +DistanceMatrix, and must always either be part of the +graph passed to the function, or passed in as a parameter.
+Default: get(edge_weight, g) +
+ +IN: distance_compare(CompareFunction cmp) +
+The function used to compare distances to determine which target +vertex is closer to the source vertex. The CompareFunction must be a +model of BinaryPredicate. The argument types must match the +value type of the WeightMap.
+ +Default: std::less<WM>with WM = typename property_traits<WeightMap>::value_type +
+ +IN: distance_combine(CombineFunction cmb) +
+The function used to combine distance to compute the distance of a +path. The CombineFunction must be a model of BinaryFunction. +The argument types must match the value type of the WeightMap. +The result type must be the same as the distance value type.
+ +Default: std::plus<WM> with WM = typename property_traits<WeightMap>::value_type +
+ +IN: distance_inf(WM inf) +
+The value used to initialize the distance for each vertex before +starting the algorithm, and to represent the distance between vertices +for which there is not path. Should be larger than any possible valid +path length. The argument type must match the value type of the +WeightMap.
+ +Default: std::numeric_limits<WM>::max() with WM = typename property_traits<WeightMap>::value_type +
+ +IN: distance_zero(WM zero) +
+The value used to represent the distance from a vertex to itself, and +to determine if a value is negative. The argument type must match the +value type of the WeightMap.
+Default: 0 +
+ +

Complexity

+ +The time complexity is O(V3). + +
+
+ + + + +
Copyright © 2002-2004 + Lauren Foutz, Rensselaer Polytechnic Institute
Scott Hill, Rensselaer Polytechnic Institute +
+ + + diff --git a/doc/fruchterman_reingold.html b/doc/fruchterman_reingold.html new file mode 100644 index 00000000..843b78fd --- /dev/null +++ b/doc/fruchterman_reingold.html @@ -0,0 +1,206 @@ + + +Boost Graph Library: Fruchterman-Reingold Force-Directed Layout + +C++ Boost + +
+ +fruchterman_reingold_force_directed_layout + + + +

+

+// named parameter version
+template<typename Graph, typename PositionMap, typename Dim, typename Param,
+	 typename Tag, typename Rest>
+void
+fruchterman_reingold_force_directed_layout
+  (const Graph&    g,
+   PositionMap     position,
+   Dim             width,
+   Dim             height,
+   const bgl_named_params<Param, Tag, Rest>& params);
+
+// non-named parameter version
+template<typename Graph, typename PositionMap, typename Dim,
+         typename AttractiveForce, typename RepulsiveForce,
+         typename ForcePairs, typename DisplacementMap, typename Cooling>
+void
+fruchterman_reingold_force_directed_layout
+ (const Graph&    g,
+  PositionMap     position,
+  Dim             width,
+  Dim             height,
+  AttractiveForce fa,
+  RepulsiveForce  fr,
+  ForcePairs      fp,
+  Cooling         cool,
+  DisplacementMap displacement);
+
+template<typename Graph, typename PositionMap, typename Dim>
+void
+fruchterman_reingold_force_directed_layout(const Graph&    g,
+			     		   PositionMap     position,
+			     		   Dim             width,
+			     		   Dim             height);
+
+ +

This algorithm [58] performs layout of +unweighted, undirected graphs. Unlike the Kamada-Kawai layout +algorithm, this algorithm directly supports the layout of disconnected +graphs (but see the force_pairs named parameter). It is a +force-directed algorithm, meaning that vertex layout is +determined by the forces pulling vertices together and pushing them +apart. Attractive forces occur between adjacent vertices only, whereas +repulsive forces occur between every pair of vertices. Each iteration +computes the sum of the forces on each vertex, then moves the vertices +to their new positions. The movement of vertices is mitigated by the +temperature of the system for that iteration: as the algorithm +progresses through successive iterations, the temperature should +decrease so that vertices settle in place. The cooling schedule, +attractive forces, and repulsive forces can be provided by the user. + +

The vertices are often placed randomly prior to execution of this algorithm via random_graph_layout. + +

Where Defined

+ +boost/graph/fruchterman_reingold.hpp + +

Parameters

+ +IN: const Graph& g +
+ The graph object on which the algorithm will be applied. + The type Graph must be a model of + Vertex And Edge List Graph. +
+ +IN/OUT: PositionMap position +
+ The property map that stores the position of each vertex. It should + typically be initialized with the vertices at random locations (use + random_graph_layout). The + type PositionMap must be a model of Lvalue Property + Map such that the vertex descriptor type of Graph is + convertible to its key type. Its value type must be a structure + with fields x and y, representing the coordinates + of the vertex. +
+ +IN: Dim width +
+ The width of the display area in which layout should occur. On + termination of the algorithm, the x coordinates of all + vertices will fall in [-width/2, width/2]. +
+ +IN: Dim height +
+ The height of the display area in which layout should occur. On + termination of the algorithm, the y coordinates of all + vertices will fall in [-height/2, height/2]. +
+ +

Named Parameters

+ +IN: attractive_force(AttractiveForce fa) +
+Computes the magnitude of the attractive force between two adjacent +vertices. The function object fa must accept four +parameters: the edge descriptor, k, the distance between the +vertices, and the graph. k is the square root of the ratio +of the display area to the number of vertices.
+Default: square_distance_attractive_force(), which +computes the attractive force as dist2/k. +
+ +IN: repulsive_force(RepulsiveForce fr) +
+Computes the magnitude of the repulsive force between any two +vertices. The function object fa must accept five +parameters: the two vertex descriptors, k, the distance between the +vertices, and the graph. k is the square root of the ratio +of the display area to the number of vertices.
+Default: square_distance_repsulsive_force(), which +computes the repulsive force as k2/dist. +
+ +IN: force_pairs(ForcePairs fp) +
+Enumerates the pairs of vertices on which the repulsive force should +be applied. fp is a function object taking two parameters: +the graph g and a binary function object that should be +passed each pair of vertices to be considered. The basic formulation +of the Fruchterman-Reingold algorithm computes repulsive forces +between all pairs of vertices (pass all_force_pairs() for +this parameter), which is functional for disconnected graphs but +tends to push the connected components toward the edges of the +display area. The grid variant of the algorithm places a grid over +the display area and only computes repulsive forces among vertices +within each rectangle in the grid. The grid variant can be more +efficient than the basic formulation and tends to produce better +layouts for disconnected graphs, but is not better overall: pass +make_grid_force_pairs(width, height, position) as this +parameter to use the grid variant. Other enumeration strategies may +yield better results for particular graphs.
+Default: make_grid_force_pairs(width, height, position) +
+ +IN: cooling(Cooling cool) +
+Determines the cooling schedule for the algorithm, which affects the +rate of movement of vertices and termination of the algorithm. The +cool parameter is a nullary function object (i.e., one that +takes no arguments) and returns the temperature for the current +iteration. When the returned temperature is zero, the algorithm +terminates. Cooling schedules should begin with some initial +temperature and gradually reduce the temperature to zero.
+Default: linear_cooling<double>(100) +
+ +UTIL: displacement_map(DisplacementMap displacement) +
+The displacement map is used to compute the amount by which each +vertex will move in each step. The DisplacementMap type +carries the same requirements as the PositionMap type.
+Default: An iterator_property_map with a value type +of simple_point<double> and using the given vertex index map. +
+ +IN: vertex_index_map(VertexIndexMap i_map) +
+ This maps each vertex to an integer in the range [0, + num_vertices(g)). This is only necessary when no + displacement map is provided. + The type VertexIndexMap must be a model of Readable Property + Map. The value type of the map must be an integer type. The + vertex descriptor type of the graph needs to be usable as the key + type of the map.
+Default: get(vertex_index, g) +
+ +

Complexity

+ +

The time complexity is O(|V|2 + |E|) for each +iteration of the algorithm in the worse case. The average case for the +grid variant is O(|V| + |E|). The number of iterations is +determined by the cooling schedule. + +
+


+ + +
Copyright © 2004 +Doug Gregor, Indiana University +
+ + + diff --git a/doc/johnson_all_pairs_shortest.html b/doc/johnson_all_pairs_shortest.html index db1e0431..0c53784c 100644 --- a/doc/johnson_all_pairs_shortest.html +++ b/doc/johnson_all_pairs_shortest.html @@ -46,7 +46,9 @@ between each pair of vertices is stored in the distance matrix D. This is one of the more time intensive graph algorithms, having a time complexity of O(V E log V). -

+

This algorithm should be used to compute shortest paths between +every pair of vertices for sparse graphs. For dense graphs, use floyd_warshall_all_pairs_shortest_paths.

Where Defined

diff --git a/doc/random_layout.html b/doc/random_layout.html new file mode 100644 index 00000000..a7ea7179 --- /dev/null +++ b/doc/random_layout.html @@ -0,0 +1,94 @@ + + +Boost Graph Library: Random Graph Layout + +C++ Boost + +
+ +random_graph_layout + + + +

+

+// non-named parameter version
+template<typename Graph, typename PositionMap, typename Dimension, 
+         typename RandomNumberGenerator>
+void
+random_graph_layout(const Graph& g, PositionMap position_map,
+                    Dimension minX, Dimension maxX, 
+                    Dimension minY, Dimension maxY,
+                    RandomNumberGenerator& gen);
+
+ +

This algorithm places the points of the graph at random +locations.

+ +

Where Defined

+ +boost/graph/random_layout.hpp + +

Parameters

+ +IN: const Graph& g +
+ The graph object on which the algorithm will be applied. + The type Graph must be a model of + Vertex And Edge List Graph. +
+ +IN/OUT: PositionMap position +
+ The property map that stores the position of each vertex. The type + PositionMap must be a model of Lvalue Property + Map such that the vertex descriptor type of Graph is + convertible to its key type. Its value type must be a structure with + fields x and y, representing the coordinates of + the vertex. +
+ +IN: Dimension minX +
+ The minimum x coordinate. +
+ +IN: Dimension maxX +
+ The maximum x coordinate. +
+ +IN: Dimension minY +
+ The minimum y coordinate. +
+ +IN: Dimension maxY +
+ The maximum y coordinate. +
+ +IN/UTIL: RandomNumberGenerator& gen +
+A random number generator that will be used to place vertices. The +type RandomNumberGenerator must model the NumberGenerator +concept. +
+ +

Complexity

+

The time complexity is O(|V|). + +
+


+ + +
Copyright © 2004 +Doug Gregor, Indiana University +
+ + + diff --git a/doc/table_of_contents.html b/doc/table_of_contents.html index 4302ada8..da8db51c 100644 --- a/doc/table_of_contents.html +++ b/doc/table_of_contents.html @@ -73,6 +73,7 @@
  • DFS Visitor
  • Dijkstra Visitor
  • Bellman Ford Visitor +
  • A* Visitor
  • Event Visitor
  • EventVisitorList Adaptors @@ -82,6 +83,7 @@
  • dfs_visitor
  • dijkstra_visitor
  • bellman_visitor +
  • astar_visitor
  • Event Visitors
      @@ -142,6 +144,7 @@
    1. dag_shortest_paths
    2. johnson_all_pairs_shortest_paths +
    3. floyd_warshall_all_pairs_shortest_paths
  • Minimum Spanning Tree Algorithms
      @@ -184,8 +187,10 @@
    1. brandes_betweenness_centrality
    2. Layout algorithms
        +
      1. random_graph_layout
      2. circle_layout
      3. kamada_kawai_spring_layout
      4. +
      5. fruchterman_reingold_force_directed_layout
    3. Clustering algorithms @@ -193,6 +198,7 @@
    4. betweenness_centrality_clustering
  • +
  • astar_search
  • diff --git a/doc/visitor_concepts.html b/doc/visitor_concepts.html index bfc3e984..54ee1ef9 100644 --- a/doc/visitor_concepts.html +++ b/doc/visitor_concepts.html @@ -42,6 +42,7 @@ the following visitor concepts:
  • DFS Visitor
  • Dijkstra Visitor
  • Bellman Ford Visitor +
  • A* Visitor
  • Event Visitor diff --git a/example/astar-cities.cpp b/example/astar-cities.cpp new file mode 100644 index 00000000..a2a11544 --- /dev/null +++ b/example/astar-cities.cpp @@ -0,0 +1,224 @@ + + +// +//======================================================================= +// Copyright (c) 2004 Kristopher Beevers +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // for sqrt + +using namespace boost; +using namespace std; + + +// auxiliary types +struct location +{ + float y, x; // lat, long +}; +typedef float cost; + +template +class city_writer { +public: + city_writer(Name n, LocMap l, float _minx, float _maxx, + float _miny, float _maxy, + unsigned int _ptx, unsigned int _pty) + : name(n), loc(l), minx(_minx), maxx(_maxx), miny(_miny), + maxy(_maxy), ptx(_ptx), pty(_pty) {} + template + void operator()(ostream& out, const Vertex& v) const { + float px = 1 - (loc[v].x - minx) / (maxx - minx); + float py = (loc[v].y - miny) / (maxy - miny); + out << "[label=\"" << name[v] << "\", pos=\"" + << static_cast(ptx * px) << "," + << static_cast(pty * py) + << "\", fontsize=\"11\"]"; + } +private: + Name name; + LocMap loc; + float minx, maxx, miny, maxy; + unsigned int ptx, pty; +}; + +template +class time_writer { +public: + time_writer(WeightMap w) : wm(w) {} + template + void operator()(ostream &out, const Edge& e) const { + out << "[label=\"" << wm[e] << "\", fontsize=\"11\"]"; + } +private: + WeightMap wm; +}; + + +// euclidean distance heuristic +template +class distance_heuristic : public astar_heuristic +{ +public: + typedef typename graph_traits::vertex_descriptor Vertex; + distance_heuristic(LocMap l, Vertex goal) + : m_location(l), m_goal(goal) {} + CostType operator()(Vertex u) + { + CostType dx = m_location[m_goal].x - m_location[u].x; + CostType dy = m_location[m_goal].y - m_location[u].y; + return ::sqrt(dx * dx + dy * dy); + } +private: + LocMap m_location; + Vertex m_goal; +}; + + +struct found_goal {}; // exception for termination + +// visitor that terminates when we find the goal +template +class astar_goal_visitor : public boost::default_astar_visitor +{ +public: + astar_goal_visitor(Vertex goal) : m_goal(goal) {} + template + void examine_vertex(Vertex u, Graph& g) { + if(u == m_goal) + throw found_goal(); + } +private: + Vertex m_goal; +}; + + +int main(int argc, char **argv) +{ + + // specify some types + typedef adjacency_list > mygraph_t; + typedef property_map::type WeightMap; + typedef mygraph_t::vertex_descriptor vertex; + typedef mygraph_t::edge_descriptor edge_descriptor; + typedef mygraph_t::vertex_iterator vertex_iterator; + typedef std::pair edge; + + // specify data + enum nodes { + Troy, LakePlacid, Plattsburgh, Massena, Watertown, Utica, + Syracuse, Rochester, Buffalo, Ithaca, Binghamton, Woodstock, + NewYork, N + }; + const char *name[] = { + "Troy", "Lake Placid", "Plattsburgh", "Massena", + "Watertown", "Utica", "Syracuse", "Rochester", "Buffalo", + "Ithaca", "Binghamton", "Woodstock", "New York" + }; + location locations[] = { // lat/long + {42.73, 73.68}, {44.28, 73.99}, {44.70, 73.46}, + {44.93, 74.89}, {43.97, 75.91}, {43.10, 75.23}, + {43.04, 76.14}, {43.17, 77.61}, {42.89, 78.86}, + {42.44, 76.50}, {42.10, 75.91}, {42.04, 74.11}, + {40.67, 73.94} + }; + edge edge_array[] = { + edge(Troy,Utica), edge(Troy,LakePlacid), + edge(Troy,Plattsburgh), edge(LakePlacid,Plattsburgh), + edge(Plattsburgh,Massena), edge(LakePlacid,Massena), + edge(Massena,Watertown), edge(Watertown,Utica), + edge(Watertown,Syracuse), edge(Utica,Syracuse), + edge(Syracuse,Rochester), edge(Rochester,Buffalo), + edge(Syracuse,Ithaca), edge(Ithaca,Binghamton), + edge(Ithaca,Rochester), edge(Binghamton,Troy), + edge(Binghamton,Woodstock), edge(Binghamton,NewYork), + edge(Syracuse,Binghamton), edge(Woodstock,Troy), + edge(Woodstock,NewYork) + }; + unsigned int num_edges = sizeof(edge_array) / sizeof(edge); + cost weights[] = { // estimated travel time (mins) + 96, 134, 143, 65, 115, 133, 117, 116, 74, 56, + 84, 73, 69, 70, 116, 147, 173, 183, 74, 71, 124 + }; + + + // create graph + mygraph_t g(N); + WeightMap weightmap = get(edge_weight, g); + for(std::size_t j = 0; j < num_edges; ++j) { + edge_descriptor e; bool inserted; + tie(e, inserted) = add_edge(edge_array[j].first, + edge_array[j].second, g); + weightmap[e] = weights[j]; + } + + + // pick random start/goal + mt19937 gen(time(0)); + vertex start = random_vertex(g, gen); + vertex goal = random_vertex(g, gen); + + + cout << "Start vertex: " << name[start] << endl; + cout << "Goal vertex: " << name[goal] << endl; + + ofstream dotfile; + dotfile.open("test-astar-cities.dot"); + write_graphviz(dotfile, g, + city_writer + (name, locations, 73.46, 78.86, 40.67, 44.93, + 480, 400), + time_writer(weightmap)); + + + vector p(num_vertices(g)); + vector d(num_vertices(g)); + try { + // call astar named parameter interface + astar_search + (g, start, + distance_heuristic + (locations, goal), + predecessor_map(&p[0]).distance_map(&d[0]). + visitor(astar_goal_visitor(goal))); + + + } catch(found_goal fg) { // found a path to the goal + list shortest_path; + for(vertex v = goal;; v = p[v]) { + shortest_path.push_front(v); + if(p[v] == v) + break; + } + cout << "Shortest path from " << name[start] << " to " + << name[goal] << ": "; + list::iterator spi = shortest_path.begin(); + cout << name[start]; + for(++spi; spi != shortest_path.end(); ++spi) + cout << " -> " << name[*spi]; + cout << endl << "Total travel time: " << d[goal] << endl; + return 0; + } + + cout << "Didn't find a path from " << name[start] << "to" + << name[goal] << "!" << endl; + return 0; + +} diff --git a/example/test-astar-cities.dot b/example/test-astar-cities.dot new file mode 100644 index 00000000..aee8107c --- /dev/null +++ b/example/test-astar-cities.dot @@ -0,0 +1,36 @@ +graph G { +0[label="Troy", pos="460,193", fontsize="11"]; +1[label="Lake Placid", pos="432,338", fontsize="11"]; +2[label="Plattsburgh", pos="480,378", fontsize="11"]; +3[label="Massena", pos="352,400", fontsize="11"]; +4[label="Watertown", pos="262,309", fontsize="11"]; +5[label="Utica", pos="322,228", fontsize="11"]; +6[label="Syracuse", pos="241,222", fontsize="11"]; +7[label="Rochester", pos="111,234", fontsize="11"]; +8[label="Buffalo", pos="0,208", fontsize="11"]; +9[label="Ithaca", pos="209,166", fontsize="11"]; +10[label="Binghamton", pos="262,134", fontsize="11"]; +11[label="Woodstock", pos="422,128", fontsize="11"]; +12[label="New York", pos="437,0", fontsize="11"]; +0--5 [label="96", fontsize="11"]; +0--1 [label="134", fontsize="11"]; +0--2 [label="143", fontsize="11"]; +1--2 [label="65", fontsize="11"]; +2--3 [label="115", fontsize="11"]; +1--3 [label="133", fontsize="11"]; +3--4 [label="117", fontsize="11"]; +4--5 [label="116", fontsize="11"]; +4--6 [label="74", fontsize="11"]; +5--6 [label="56", fontsize="11"]; +6--7 [label="84", fontsize="11"]; +7--8 [label="73", fontsize="11"]; +6--9 [label="69", fontsize="11"]; +9--10 [label="70", fontsize="11"]; +9--7 [label="116", fontsize="11"]; +10--0 [label="147", fontsize="11"]; +10--11 [label="173", fontsize="11"]; +10--12 [label="183", fontsize="11"]; +6--10 [label="74", fontsize="11"]; +11--0 [label="71", fontsize="11"]; +11--12 [label="124", fontsize="11"]; +} diff --git a/include/boost/graph/astar_search.hpp b/include/boost/graph/astar_search.hpp new file mode 100644 index 00000000..2802bb8d --- /dev/null +++ b/include/boost/graph/astar_search.hpp @@ -0,0 +1,390 @@ + + +// +//======================================================================= +// Copyright (c) 2004 Kristopher Beevers +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= +// + +#ifndef BOOST_GRAPH_ASTAR_SEARCH_HPP +#define BOOST_GRAPH_ASTAR_SEARCH_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace boost { + + + template + struct AStarHeuristicConcept { + void constraints() + { + function_requires< CopyConstructibleConcept >(); + h(u); + } + Heuristic h; + typename graph_traits::vertex_descriptor u; + }; + + + template + class astar_heuristic : public std::unary_function< + typename graph_traits::vertex_descriptor, CostType> + { + public: + typedef typename graph_traits::vertex_descriptor Vertex; + astar_heuristic() {} + CostType operator()(Vertex u) { return static_cast(0); } + }; + + + + template + struct AStarVisitorConcept { + void constraints() + { + function_requires< CopyConstructibleConcept >(); + vis.initialize_vertex(u, g); + vis.discover_vertex(u, g); + vis.examine_vertex(u, g); + vis.examine_edge(e, g); + vis.edge_relaxed(e, g); + vis.edge_not_relaxed(e, g); + vis.black_target(e, g); + vis.finish_vertex(u, g); + } + Visitor vis; + Graph g; + typename graph_traits::vertex_descriptor u; + typename graph_traits::edge_descriptor e; + }; + + + template + class astar_visitor : public bfs_visitor { + public: + astar_visitor() {} + astar_visitor(Visitors vis) + : bfs_visitor(vis) {} + + template + void edge_relaxed(Edge e, Graph& g) { + invoke_visitors(this->m_vis, e, g, on_edge_relaxed()); + } + template + void edge_not_relaxed(Edge e, Graph& g) { + invoke_visitors(this->m_vis, e, g, on_edge_not_relaxed()); + } + private: + template + void tree_edge(Edge e, Graph& g) {} + template + void non_tree_edge(Edge e, Graph& g) {} + }; + template + astar_visitor + make_astar_visitor(Visitors vis) { + return astar_visitor(vis); + } + typedef astar_visitor<> default_astar_visitor; + + + namespace detail { + + template + struct astar_bfs_visitor + { + + typedef typename property_traits::value_type C; + typedef typename property_traits::value_type ColorValue; + typedef color_traits Color; + + + astar_bfs_visitor(AStarHeuristic h, UniformCostVisitor vis, + UpdatableQueue& Q, PredecessorMap p, + CostMap c, DistanceMap d, WeightMap w, + ColorMap col, BinaryFunction combine, + BinaryPredicate compare, C zero) + : m_h(h), m_vis(vis), m_Q(Q), m_predecessor(p), m_cost(c), + m_distance(d), m_weight(w), m_color(col), + m_combine(combine), m_compare(compare), m_zero(zero) {} + + + template + void initialize_vertex(Vertex u, Graph& g) { + m_vis.initialize_vertex(u, g); + } + template + void discover_vertex(Vertex u, Graph& g) { + m_vis.discover_vertex(u, g); + } + template + void examine_vertex(Vertex u, Graph& g) { + m_vis.examine_vertex(u, g); + } + template + void finish_vertex(Vertex u, Graph& g) { + m_vis.finish_vertex(u, g); + } + template + void examine_edge(Edge e, Graph& g) { + if (m_compare(get(m_weight, e), m_zero)) + throw negative_edge(); + m_vis.examine_edge(e, g); + } + template + void non_tree_edge(Edge, Graph&) {} + + + + template + void tree_edge(Edge e, Graph& g) { + m_decreased = relax(e, g, m_weight, m_predecessor, m_distance, + m_combine, m_compare); + if(m_decreased) { + m_vis.edge_relaxed(e, g); + put(m_cost, target(e, g), + m_combine(get(m_distance, target(e, g)), + m_h(target(e, g)))); + } else + m_vis.edge_not_relaxed(e, g); + } + + + template + void gray_target(Edge e, Graph& g) { + m_decreased = relax(e, g, m_weight, m_predecessor, m_distance, + m_combine, m_compare); + if(m_decreased) { + put(m_cost, target(e, g), + m_combine(get(m_distance, target(e, g)), + m_h(target(e, g)))); + m_Q.update(target(e, g)); + m_vis.edge_relaxed(e, g); + } else + m_vis.edge_not_relaxed(e, g); + } + + + template + void black_target(Edge e, Graph& g) { + m_decreased = relax(e, g, m_weight, m_predecessor, m_distance, + m_combine, m_compare); + if(m_decreased) { + m_vis.edge_relaxed(e, g); + put(m_cost, target(e, g), + m_combine(get(m_distance, target(e, g)), + m_h(target(e, g)))); + m_Q.push(target(e, g)); + put(m_color, target(e, g), Color::gray()); + m_vis.black_target(e, g); + } else + m_vis.edge_not_relaxed(e, g); + } + + + + AStarHeuristic m_h; + UniformCostVisitor m_vis; + UpdatableQueue& m_Q; + PredecessorMap m_predecessor; + CostMap m_cost; + DistanceMap m_distance; + WeightMap m_weight; + ColorMap m_color; + BinaryFunction m_combine; + BinaryPredicate m_compare; + bool m_decreased; + C m_zero; + + }; + + } // namespace detail + + + + template + inline void + astar_search_no_init + (VertexListGraph &g, + typename graph_traits::vertex_descriptor s, + AStarHeuristic h, AStarVisitor vis, + PredecessorMap predecessor, CostMap cost, + DistanceMap distance, WeightMap weight, + ColorMap color, VertexIndexMap index_map, + CompareFunction compare, CombineFunction combine, + CostInf inf, CostZero zero) + { + typedef indirect_cmp IndirectCmp; + IndirectCmp icmp(cost, compare); + + typedef typename graph_traits::vertex_descriptor + Vertex; + typedef mutable_queue, + IndirectCmp, VertexIndexMap> + MutableQueue; + MutableQueue Q(num_vertices(g), icmp, index_map); + + detail::astar_bfs_visitor + bfs_vis(h, vis, Q, predecessor, cost, distance, weight, + color, combine, compare, zero); + + breadth_first_visit(g, s, Q, bfs_vis, color); + } + + + // Non-named parameter interface + template + inline void + astar_search + (VertexListGraph &g, + typename graph_traits::vertex_descriptor s, + AStarHeuristic h, AStarVisitor vis, + PredecessorMap predecessor, CostMap cost, + DistanceMap distance, WeightMap weight, + VertexIndexMap index_map, ColorMap color, + CompareFunction compare, CombineFunction combine, + CostInf inf, CostZero zero) + { + + typedef typename property_traits::value_type ColorValue; + typedef color_traits Color; + typename graph_traits::vertex_iterator ui, ui_end; + for (tie(ui, ui_end) = vertices(g); ui != ui_end; ++ui) { + put(color, *ui, Color::white()); + put(distance, *ui, inf); + put(cost, *ui, inf); + put(predecessor, *ui, *ui); + } + put(distance, s, zero); + put(cost, s, h(s)); + + astar_search_no_init + (g, s, h, vis, predecessor, cost, distance, weight, + color, index_map, compare, combine, inf, zero); + + } + + + + namespace detail { + template + inline void + astar_dispatch2 + (VertexListGraph& g, + typename graph_traits::vertex_descriptor s, + AStarHeuristic h, CostMap cost, DistanceMap distance, + WeightMap weight, IndexMap index_map, ColorMap color, + const Params& params) + { + dummy_property_map p_map; + typedef typename property_traits::value_type C; + astar_search + (g, s, h, + choose_param(get_param(params, graph_visitor), + make_astar_visitor(null_visitor())), + choose_param(get_param(params, vertex_predecessor), p_map), + cost, distance, weight, index_map, color, + choose_param(get_param(params, distance_compare_t()), + std::less()), + choose_param(get_param(params, distance_combine_t()), + closed_plus()), + choose_param(get_param(params, distance_inf_t()), + std::numeric_limits::max()), + choose_param(get_param(params, distance_zero_t()), + C())); + } + + template + inline void + astar_dispatch1 + (VertexListGraph& g, + typename graph_traits::vertex_descriptor s, + AStarHeuristic h, CostMap cost, DistanceMap distance, + WeightMap weight, IndexMap index_map, ColorMap color, + const Params& params) + { + typedef typename property_traits::value_type D; + typename std::vector::size_type + n = is_default_param(distance) ? num_vertices(g) : 1; + std::vector distance_map(n); + n = is_default_param(cost) ? num_vertices(g) : 1; + std::vector cost_map(n); + std::vector color_map(num_vertices(g)); + default_color_type c = white_color; + + detail::astar_dispatch2 + (g, s, h, + choose_param(cost, make_iterator_property_map + (cost_map.begin(), index_map, + cost_map[0])), + choose_param(distance, make_iterator_property_map + (distance_map.begin(), index_map, + distance_map[0])), + weight, index_map, + choose_param(color, make_iterator_property_map + (color_map.begin(), index_map, c)), + params); + } + } // namespace detail + + + // Named parameter interface + template + void + astar_search + (VertexListGraph &g, + typename graph_traits::vertex_descriptor s, + AStarHeuristic h, const bgl_named_params& params) + { + + detail::astar_dispatch1 + (g, s, h, + get_param(params, vertex_rank), + get_param(params, vertex_distance), + choose_const_pmap(get_param(params, edge_weight), g, edge_weight), + choose_const_pmap(get_param(params, vertex_index), g, vertex_index), + get_param(params, vertex_color), + params); + + } + +} // namespace boost + +#endif // BOOST_GRAPH_ASTAR_SEARCH_HPP diff --git a/include/boost/graph/bellman_ford_shortest_paths.hpp b/include/boost/graph/bellman_ford_shortest_paths.hpp index 174f38b8..34c6587f 100644 --- a/include/boost/graph/bellman_ford_shortest_paths.hpp +++ b/include/boost/graph/bellman_ford_shortest_paths.hpp @@ -120,6 +120,8 @@ namespace boost { typedef typename property_traits::value_type D_value; typedef typename property_traits::value_type W_value; + D_value inf = (std::numeric_limits::max)(); + typename GTraits::edge_iterator i, end; for (Size k = 0; k < N; ++k) { @@ -137,8 +139,8 @@ namespace boost { } for (tie(i, end) = edges(g); i != end; ++i) - if (compare(combine(get(distance, source(*i, g)), - get(weight, *i)), + if (compare(inf_combine(get(distance, source(*i, g)), + get(weight, *i), inf, combine, compare), get(distance, target(*i,g)))) { v.edge_not_minimized(*i, g); diff --git a/include/boost/graph/floyd_warshall_shortest.hpp b/include/boost/graph/floyd_warshall_shortest.hpp new file mode 100644 index 00000000..3dba66bd --- /dev/null +++ b/include/boost/graph/floyd_warshall_shortest.hpp @@ -0,0 +1,240 @@ +// Copyright 2002 Rensselaer Polytechnic Institute + +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Authors: Lauren Foutz +// Scott Hill + +/* + This file implements the functions + + template + bool floyd_warshall_initialized_all_pairs_shortest_paths( + const VertexListGraph& g, DistanceMatrix& d, + const bgl_named_params& params) + + AND + + template + bool floyd_warshall_all_pairs_shortest_paths( + const VertexAndEdgeListGraph& g, DistanceMatrix& d, + const bgl_named_params& params) +*/ + + +#ifndef BOOST_GRAPH_FLOYD_WARSHALL_HPP +#define BOOST_GRAPH_FLOYD_WARSHALL_HPP + +#include +#include +#include +#include +#include + +namespace boost +{ + + template + bool floyd_warshall_initialized_all_pairs_shortest_paths( + const VertexListGraph& g, DistanceMatrix& d, + const BinaryPredicate& compare, + const BinaryFunction& combine, const Infinity& inf, + const Zero& zero) + { + function_requires >(); + + return detail::floyd_warshall_dispatch(g, d, compare, combine, + inf, zero); + } + + + + template + bool floyd_warshall_all_pairs_shortest_paths( + const VertexAndEdgeListGraph& g, + DistanceMatrix& d, const WeightMap& w, + const BinaryPredicate& compare, const BinaryFunction& combine, + const Infinity& inf, const Zero& zero) + { + function_requires >(); + function_requires >(); + function_requires >(); + + typename graph_traits::vertex_iterator + firstv, lastv, firstv2, lastv2; + typename graph_traits::edge_iterator first, last; + + + for(tie(firstv, lastv) = vertices(g); firstv != lastv; firstv++) + for(tie(firstv2, lastv2) = vertices(g); firstv2 != lastv2; firstv2++) + d[*firstv][*firstv2] = inf; + + + for(tie(firstv, lastv) = vertices(g); firstv != lastv; firstv++) + d[*firstv][*firstv] = 0; + + + for(tie(first, last) = edges(g); first != last; first++) + { + if (d[source(*first, g)][target(*first, g)] != inf) + d[source(*first, g)][target(*first, g)] = + std::min(get(w, *first), + d[source(*first, g)][target(*first, g)]); + else + d[source(*first, g)][target(*first, g)] = get(w, *first); + } + + bool is_undirected = is_same::directed_category, + undirected_tag>::value; + if (is_undirected) + { + for(tie(first, last) = edges(g); first != last; first++) + { + if (d[target(*first, g)][source(*first, g)] != inf) + d[target(*first, g)][source(*first, g)] = + std::min(get(w, *first), + d[target(*first, g)][source(*first, g)]); + else + d[target(*first, g)][source(*first, g)] = get(w, *first); + } + } + + + return detail::floyd_warshall_dispatch(g, d, compare, combine, + inf, zero); + } + + + namespace detail { + template + bool floyd_warshall_dispatch(const VertexListGraph& g, + DistanceMatrix& d, const BinaryPredicate &compare, + const BinaryFunction &combine, const Infinity& inf, + const Zero& zero) + { + typename graph_traits::vertex_iterator + i, lasti, j, lastj, k, lastk; + + + for (tie(k, lastk) = vertices(g); k != lastk; k++) + for (tie(i, lasti) = vertices(g); i != lasti; i++) + for (tie(j, lastj) = vertices(g); j != lastj; j++) + { + d[*i][*j] = std::min(d[*i][*j], + inf_combine(d[*i][*k], d[*k][*j], inf, combine, + compare), compare); + } + + + for (tie(i, lasti) = vertices(g); i != lasti; i++) + if (compare(d[*i][*i], zero)) + return false; + return true; + } + + + + template + bool floyd_warshall_init_dispatch(const VertexListGraph& g, + DistanceMatrix& d, WeightMap w, + const bgl_named_params& params) + { + typedef typename property_traits::value_type WM; + + return floyd_warshall_initialized_all_pairs_shortest_paths(g, d, + choose_param(get_param(params, distance_compare_t()), + std::less()), + choose_param(get_param(params, distance_combine_t()), + std::plus()), + choose_param(get_param(params, distance_inf_t()), + std::numeric_limits::max()), + choose_param(get_param(params, distance_zero_t()), + WM())); + } + + + + template + bool floyd_warshall_noninit_dispatch(const VertexAndEdgeListGraph& g, + DistanceMatrix& d, WeightMap w, + const bgl_named_params& params) + { + typedef typename property_traits::value_type WM; + + return floyd_warshall_all_pairs_shortest_paths(g, d, w, + choose_param(get_param(params, distance_compare_t()), + std::less()), + choose_param(get_param(params, distance_combine_t()), + std::plus()), + choose_param(get_param(params, distance_inf_t()), + std::numeric_limits::max()), + choose_param(get_param(params, distance_zero_t()), + WM())); + } + + + } // namespace detail + + + + template + bool floyd_warshall_initialized_all_pairs_shortest_paths( + const VertexListGraph& g, DistanceMatrix& d, + const bgl_named_params& params) + { + return detail::floyd_warshall_init_dispatch(g, d, + choose_const_pmap(get_param(params, edge_weight), g, edge_weight), + params); + } + + template + bool floyd_warshall_initialized_all_pairs_shortest_paths( + const VertexListGraph& g, DistanceMatrix& d) + { + bgl_named_params params(0); + return detail::floyd_warshall_init_dispatch(g, d, + get(edge_weight, g), params); + } + + + + + template + bool floyd_warshall_all_pairs_shortest_paths( + const VertexAndEdgeListGraph& g, DistanceMatrix& d, + const bgl_named_params& params) + { + return detail::floyd_warshall_noninit_dispatch(g, d, + choose_const_pmap(get_param(params, edge_weight), g, edge_weight), + params); + } + + template + bool floyd_warshall_all_pairs_shortest_paths( + const VertexAndEdgeListGraph& g, DistanceMatrix& d) + { + bgl_named_params params(0); + return detail::floyd_warshall_noninit_dispatch(g, d, + get(edge_weight, g), params); + } + + +} // namespace boost + +#endif + diff --git a/include/boost/graph/fruchterman_reingold.hpp b/include/boost/graph/fruchterman_reingold.hpp new file mode 100644 index 00000000..9228b0fc --- /dev/null +++ b/include/boost/graph/fruchterman_reingold.hpp @@ -0,0 +1,378 @@ +// Copyright 2004 The Trustees of Indiana University. + +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Authors: Douglas Gregor +// Andrew Lumsdaine +#ifndef BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP +#define BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { + +struct square_distance_attractive_force { + template + T + operator()(typename graph_traits::edge_descriptor, + T k, + T d, + const Graph&) const + { + return d * d / k; + } +}; + +struct square_distance_repulsive_force { + template + T + operator()(typename graph_traits::vertex_descriptor, + typename graph_traits::vertex_descriptor, + T k, + T d, + const Graph&) const + { + return k * k / d; + } +}; + +template +struct linear_cooling { + typedef T result_type; + + linear_cooling(std::size_t iterations) + : temp(T(iterations) / T(10)), step(0.1) { } + + linear_cooling(std::size_t iterations, T temp) + : temp(temp), step(temp / T(iterations)) { } + + T operator()() + { + T old_temp = temp; + temp -= step; + if (temp < T(0)) temp = T(0); + return old_temp; + } + + private: + T temp; + T step; +}; + +struct all_force_pairs +{ + template + void operator()(const Graph& g, ApplyForce apply_force) + { + typedef typename graph_traits::vertex_iterator vertex_iterator; + vertex_iterator v, end; + for (tie(v, end) = vertices(g); v != end; ++v) { + vertex_iterator u = v; + for (++u; u != end; ++u) { + apply_force(*u, *v); + apply_force(*v, *u); + } + } + } +}; + +template +struct grid_force_pairs +{ + explicit grid_force_pairs(Dim width, Dim height, PositionMap position) + : width(width), height(height), position(position) + { + using std::sqrt; + two_k = Dim(2) * sqrt(width*height); + } + + template + void operator()(const Graph& g, ApplyForce apply_force) + { + typedef typename graph_traits::vertex_iterator vertex_iterator; + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + typedef std::list bucket_t; + typedef std::vector buckets_t; + + std::size_t columns = std::size_t(width / two_k); + buckets_t buckets(num_vertices(g) / 4); + vertex_iterator v, v_end; + for (tie(v, v_end) = vertices(g); v != v_end; ++v) { + std::size_t column = std::size_t((position[*v].x - width / 2) / two_k); + std::size_t row = std::size_t((position[*v].y - height / 2) / two_k); + buckets.at(row * columns + column).push_back(*v); + } + + typedef typename buckets_t::iterator buckets_iterator; + for (buckets_iterator i = buckets.begin(); i != buckets.end(); ++i) { + typedef typename bucket_t::iterator bucket_iterator; + for (bucket_iterator u = i->begin(); u != i->end(); ++u) { + for (bucket_iterator v = i->begin(); v != i->end(); ++v) { + if (*u != *v) apply_force(*u, *v); + } + } + } + } + + private: + Dim width; + Dim height; + PositionMap position; + Dim two_k; +}; + +template +inline grid_force_pairs +make_grid_force_pairs(Dim width, Dim height, const PositionMap& position) +{ return grid_force_pairs(width, height, position); } + +template +void +scale_graph(const Graph& g, PositionMap position, + Dim left, Dim top, Dim right, Dim bottom) +{ + if (num_vertices(g) == 0) return; + + if (bottom > top) { + using std::swap; + swap(bottom, top); + } + + typedef typename graph_traits::vertex_iterator vertex_iterator; + + // Find min/max ranges + Dim minX = position[*vertices(g).first].x, maxX = minX; + Dim minY = position[*vertices(g).first].y, maxY = minY; + vertex_iterator vi, vi_end; + for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { + using std::min; // TBD: eric's tricks + using std::max; + minX = min(minX, position[*vi].x); + maxX = max(maxX, position[*vi].x); + minY = min(minY, position[*vi].y); + maxY = max(maxY, position[*vi].y); + } + + // Scale to bounding box provided + for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { + position[*vi].x = ((position[*vi].x - minX) / (maxX - minX)) + * (right - left) + left; + position[*vi].y = ((position[*vi].y - minY) / (maxY - minY)) + * (top - bottom) + bottom; + } +} + +namespace detail { + template + struct fr_apply_force + { + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + + fr_apply_force(const PositionMap& position, + const DisplacementMap& displacement, + RepulsiveForce repulsive_force, Dim k, const Graph& g) + : position(position), displacement(displacement), + repulsive_force(repulsive_force), k(k), g(g) + { } + + void operator()(vertex_descriptor u, vertex_descriptor v) + { + if (u != v) { + using std::sqrt; + + Dim delta_x = position[v].x - position[u].x; + Dim delta_y = position[v].y - position[u].y; + Dim dist = sqrt(delta_x * delta_x + delta_y * delta_y); + Dim fr = repulsive_force(u, v, k, dist, g); + displacement[v].x += delta_x / dist * fr; + displacement[v].y += delta_y / dist * fr; + } + } + + private: + PositionMap position; + DisplacementMap displacement; + RepulsiveForce repulsive_force; + Dim k; + const Graph& g; + }; + +} // end namespace detail + +template +void +fruchterman_reingold_force_directed_layout + (const Graph& g, + PositionMap position, + Dim width, + Dim height, + AttractiveForce attractive_force, + RepulsiveForce repulsive_force, + ForcePairs force_pairs, + Cooling cool, + DisplacementMap displacement) +{ + typedef typename graph_traits::vertex_iterator vertex_iterator; + typedef typename graph_traits::vertex_descriptor vertex_descriptor; + typedef typename graph_traits::edge_iterator edge_iterator; + + using std::sqrt; + + Dim area = width * height; + // assume positions are initialized randomly + Dim k = sqrt(area / num_vertices(g)); + + detail::fr_apply_force + apply_force(position, displacement, repulsive_force, k, g); + + while (Dim temp = cool()) { + // Calculate repulsive forces + vertex_iterator v, v_end; + for (tie(v, v_end) = vertices(g); v != v_end; ++v) { + displacement[*v].x = 0; + displacement[*v].y = 0; + } + force_pairs(g, apply_force); + + // Calculate attractive forces + edge_iterator e, e_end; + for (tie(e, e_end) = edges(g); e != e_end; ++e) { + vertex_descriptor v = source(*e, g); + vertex_descriptor u = target(*e, g); + Dim delta_x = position[v].x - position[u].x; + Dim delta_y = position[v].y - position[u].y; + Dim dist = sqrt(delta_x * delta_x + delta_y * delta_y); + Dim fa = attractive_force(*e, k, dist, g); + + displacement[v].x -= delta_x / dist * fa; + displacement[v].y -= delta_y / dist * fa; + displacement[u].x += delta_x / dist * fa; + displacement[u].y += delta_y / dist * fa; + } + + // Update positions + for (tie(v, v_end) = vertices(g); v != v_end; ++v) { + using std::min; // TBD: use Eric's crazy hacks here + using std::max; // TBD: use Eric's crazy hacks here + Dim disp_size = sqrt(displacement[*v].x * displacement[*v].x + + displacement[*v].y * displacement[*v].y); + position[*v].x += displacement[*v].x / disp_size * min(disp_size, temp); + position[*v].y += displacement[*v].y / disp_size * min(disp_size, temp); + position[*v].x = min(width / 2, max(-width / 2, position[*v].x)); + position[*v].y = min(height / 2, max(-height / 2, position[*v].y)); + } + } +} + +namespace detail { + template + struct fr_force_directed_layout + { + template + static void + run(const Graph& g, + PositionMap position, + Dim width, + Dim height, + AttractiveForce attractive_force, + RepulsiveForce repulsive_force, + ForcePairs force_pairs, + Cooling cool, + DisplacementMap displacement, + const bgl_named_params&) + { + fruchterman_reingold_force_directed_layout + (g, position, width, height, attractive_force, repulsive_force, + force_pairs, cool, displacement); + } + }; + + template<> + struct fr_force_directed_layout + { + template + static void + run(const Graph& g, + PositionMap position, + Dim width, + Dim height, + AttractiveForce attractive_force, + RepulsiveForce repulsive_force, + ForcePairs force_pairs, + Cooling cool, + error_property_not_found, + const bgl_named_params& params) + { + std::vector > displacements(num_vertices(g)); + fruchterman_reingold_force_directed_layout + (g, position, width, height, attractive_force, repulsive_force, + force_pairs, cool, + make_iterator_property_map + (displacements.begin(), + choose_const_pmap(get_param(params, vertex_index), g, + vertex_index))); + } + }; + +} // end namespace detail + +template +void +fruchterman_reingold_force_directed_layout + (const Graph& g, + PositionMap position, + Dim width, + Dim height, + const bgl_named_params& params) +{ + typedef typename property_value, + vertex_displacement_t>::type D; + + detail::fr_force_directed_layout::run + (g, position, width, height, + choose_param(get_param(params, attractive_force_t()), + square_distance_attractive_force()), + choose_param(get_param(params, repulsive_force_t()), + square_distance_repulsive_force()), + choose_param(get_param(params, force_pairs_t()), + make_grid_force_pairs(width, height, position)), + choose_param(get_param(params, cooling_t()), + linear_cooling(100)), + get_param(params, vertex_displacement_t()), + params); +} + +template +void +fruchterman_reingold_force_directed_layout(const Graph& g, + PositionMap position, + Dim width, + Dim height) +{ + fruchterman_reingold_force_directed_layout + (g, position, width, height, + attractive_force(square_distance_attractive_force())); +} + +} // end namespace boost + +#endif // BOOST_GRAPH_FRUCHTERMAN_REINGOLD_FORCE_DIRECTED_LAYOUT_HPP diff --git a/include/boost/graph/named_function_params.hpp b/include/boost/graph/named_function_params.hpp index 10d342e6..92dd108d 100644 --- a/include/boost/graph/named_function_params.hpp +++ b/include/boost/graph/named_function_params.hpp @@ -45,6 +45,11 @@ namespace boost { struct vertex_max_invariant_t { }; struct orig_to_copy_t { }; struct root_vertex_t { }; + struct attractive_force_t { }; + struct repulsive_force_t { }; + struct force_pairs_t { }; + struct cooling_t { }; + struct vertex_displacement_t { }; namespace detail { template @@ -284,6 +289,42 @@ namespace boost { return Params(c, *this); } + template + bgl_named_params + displacement_map(const VertexDisplacement& c) const { + typedef bgl_named_params Params; + return Params(c, *this); + } + + template + bgl_named_params + attractive_force(const AttractiveForce& c) { + typedef bgl_named_params Params; + return Params(c, *this); + } + + template + bgl_named_params + repulsive_force(const RepulsiveForce& c) { + typedef bgl_named_params Params; + return Params(c, *this); + } + + template + bgl_named_params + force_pairs(const ForcePairs& c) { + typedef bgl_named_params Params; + return Params(c, *this); + } + + template + bgl_named_params + cooling(const Cooling& c) { + typedef bgl_named_params Params; + return Params(c, *this); + } + + }; template @@ -484,6 +525,41 @@ namespace boost { return Params(c); } + template + bgl_named_params + displacement_map(const VertexDisplacement& c) { + typedef bgl_named_params Params; + return Params(c); + } + + template + bgl_named_params + attractive_force(const AttractiveForce& c) { + typedef bgl_named_params Params; + return Params(c); + } + + template + bgl_named_params + repulsive_force(const RepulsiveForce& c) { + typedef bgl_named_params Params; + return Params(c); + } + + template + bgl_named_params + force_pairs(const ForcePairs& c) { + typedef bgl_named_params Params; + return Params(c); + } + + template + bgl_named_params + cooling(const Cooling& c) { + typedef bgl_named_params Params; + return Params(c); + } + //=========================================================================== // Functions for extracting parameters from bgl_named_params diff --git a/include/boost/graph/random_layout.hpp b/include/boost/graph/random_layout.hpp new file mode 100644 index 00000000..7f216122 --- /dev/null +++ b/include/boost/graph/random_layout.hpp @@ -0,0 +1,49 @@ +// Copyright 2004 The Trustees of Indiana University. + +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Authors: Douglas Gregor +// Andrew Lumsdaine +#ifndef BOOST_GRAPH_RANDOM_LAYOUT_HPP +#define BOOST_GRAPH_RANDOM_LAYOUT_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { + +template +void +random_graph_layout(const Graph& g, PositionMap position_map, + Dimension minX, Dimension maxX, + Dimension minY, Dimension maxY, + RandomNumberGenerator& gen) +{ + typedef typename mpl::if_, + uniform_int, + uniform_real >::type distrib_t; + typedef typename mpl::if_, + RandomNumberGenerator&, + uniform_01 > + ::type gen_t; + + gen_t my_gen(gen); + distrib_t x(minX, maxX); + distrib_t y(minY, maxY); + typename graph_traits::vertex_iterator vi, vi_end; + for(tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) { + position_map[*vi].x = x(my_gen); + position_map[*vi].y = y(my_gen); + } +} + +} // end namespace boost + +#endif // BOOST_GRAPH_RANDOM_LAYOUT_HPP diff --git a/include/boost/graph/relax.hpp b/include/boost/graph/relax.hpp index 74b3261e..240d5070 100644 --- a/include/boost/graph/relax.hpp +++ b/include/boost/graph/relax.hpp @@ -1,6 +1,8 @@ // //======================================================================= // Copyright 1997, 1998, 1999, 2000 University of Notre Dame. +// Copyright 2002 Rensselaer Polytechnic Institute +// // Authors: Andrew Lumsdaine, Lie-Quan Lee, Jeremy G. Siek // // This file is part of the Boost Graph Library @@ -25,6 +27,15 @@ //======================================================================= // +// Copyright 2002 Rensselaer Polytechnic Institute + +// Use, modification and distribution is subject to the Boost Software +// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +// Authors: Lauren Foutz +// Scott Hill + #ifndef BOOST_GRAPH_RELAX_HPP #define BOOST_GRAPH_RELAX_HPP @@ -35,6 +46,18 @@ namespace boost { + template + inline MatrixValue inf_combine(MatrixValue a, MatrixValue b, + MatrixValue inf, BinaryFunction combine, + BinaryPredicate compare) + { + if(compare(a, inf) && compare(b, inf)) + return combine(a, b); + else + return inf; + } + // The following version of the plus functor prevents // problems due to overflow at positive infinity. @@ -70,13 +93,15 @@ namespace boost { typedef typename property_traits::value_type W; D d_u = get(d, u), d_v = get(d, v); W w_e = get(w, e); - - if ( compare(combine(d_u, w_e), d_v) ) { - put(d, v, combine(d_u, w_e)); + D inf = (std::numeric_limits::max)(); + + if ( compare(inf_combine(d_u, w_e, inf, combine, compare), d_v) ) { + put(d, v, inf_combine(d_u, w_e, inf, combine, compare)); put(p, v, u); return true; - } else if (is_undirected && compare(combine(d_v, w_e), d_u)) { - put(d, u, combine(d_v, w_e)); + } else if (is_undirected + && compare(inf_combine(d_v, w_e, inf, combine, compare), d_u)) { + put(d, u, inf_combine(d_v, w_e, inf, combine, compare)); put(p, u, v); return true; } else diff --git a/include/boost/graph/simple_point.hpp b/include/boost/graph/simple_point.hpp new file mode 100644 index 00000000..915f4f7c --- /dev/null +++ b/include/boost/graph/simple_point.hpp @@ -0,0 +1,15 @@ +#ifndef BOOST_GRAPH_SIMPLE_POINT_HPP +#define BOOST_GRAPH_SIMPLE_POINT_HPP + +namespace boost { + +template +struct simple_point +{ + T x; + T y; +}; + +} // end namespace boost + +#endif // BOOST_GRAPH_SIMPLE_POINT_HPP diff --git a/test/Jamfile b/test/Jamfile index 346db888..e72bb720 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -58,6 +58,9 @@ test-suite graph : [ run bundled_properties.cpp ] + [ run floyd_warshall_test.cpp ] + + [ run astar_search_test.cpp ] ; # Run SDB tests only when -sSDB= is set. diff --git a/test/astar_search_test.cpp b/test/astar_search_test.cpp new file mode 100644 index 00000000..3e158310 --- /dev/null +++ b/test/astar_search_test.cpp @@ -0,0 +1,213 @@ + + +// +//======================================================================= +// Copyright (c) 2004 Kristopher Beevers +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +//======================================================================= +// + + +#include +#include +#include +#include +#include +#include +#include +#include +#include // for sqrt + +using namespace boost; +using namespace std; + + +// auxiliary types +struct location +{ + float y, x; // lat, long +}; +typedef float cost; + +template +class city_writer { +public: + city_writer(Name n, LocMap l, float _minx, float _maxx, + float _miny, float _maxy, + unsigned int _ptx, unsigned int _pty) + : name(n), loc(l), minx(_minx), maxx(_maxx), miny(_miny), + maxy(_maxy), ptx(_ptx), pty(_pty) {} + template + void operator()(ostream& out, const Vertex& v) const { + float px = 1 - (loc[v].x - minx) / (maxx - minx); + float py = (loc[v].y - miny) / (maxy - miny); + out << "[label=\"" << name[v] << "\", pos=\"" + << static_cast(ptx * px) << "," + << static_cast(pty * py) + << "\", fontsize=\"11\"]"; + } +private: + Name name; + LocMap loc; + float minx, maxx, miny, maxy; + unsigned int ptx, pty; +}; + +template +class time_writer { +public: + time_writer(WeightMap w) : wm(w) {} + template + void operator()(ostream &out, const Edge& e) const { + out << "[label=\"" << wm[e] << "\", fontsize=\"11\"]"; + } +private: + WeightMap wm; +}; + + +// euclidean distance heuristic +template +class distance_heuristic : public astar_heuristic +{ +public: + typedef typename graph_traits::vertex_descriptor Vertex; + distance_heuristic(LocMap l, Vertex goal) + : m_location(l), m_goal(goal) {} + CostType operator()(Vertex u) + { + CostType dx = m_location[m_goal].x - m_location[u].x; + CostType dy = m_location[m_goal].y - m_location[u].y; + return ::sqrt(dx * dx + dy * dy); + } +private: + LocMap m_location; + Vertex m_goal; +}; + + +struct found_goal {}; // exception for termination + +// visitor that terminates when we find the goal +template +class astar_goal_visitor : public boost::default_astar_visitor +{ +public: + astar_goal_visitor(Vertex goal) : m_goal(goal) {} + template + void examine_vertex(Vertex u, Graph& g) { + if(u == m_goal) + throw found_goal(); + } +private: + Vertex m_goal; +}; + + +int main(int argc, char **argv) +{ + + // specify some types + typedef adjacency_list > mygraph_t; + typedef property_map::type WeightMap; + typedef mygraph_t::vertex_descriptor vertex; + typedef mygraph_t::edge_descriptor edge_descriptor; + typedef mygraph_t::vertex_iterator vertex_iterator; + typedef std::pair edge; + + // specify data + enum nodes { + Troy, LakePlacid, Plattsburgh, Massena, Watertown, Utica, + Syracuse, Rochester, Buffalo, Ithaca, Binghamton, Woodstock, + NewYork, N + }; + const char *name[] = { + "Troy", "Lake Placid", "Plattsburgh", "Massena", + "Watertown", "Utica", "Syracuse", "Rochester", "Buffalo", + "Ithaca", "Binghamton", "Woodstock", "New York" + }; + location locations[] = { // lat/long + {42.73, 73.68}, {44.28, 73.99}, {44.70, 73.46}, + {44.93, 74.89}, {43.97, 75.91}, {43.10, 75.23}, + {43.04, 76.14}, {43.17, 77.61}, {42.89, 78.86}, + {42.44, 76.50}, {42.10, 75.91}, {42.04, 74.11}, + {40.67, 73.94} + }; + edge edge_array[] = { + edge(Troy,Utica), edge(Troy,LakePlacid), + edge(Troy,Plattsburgh), edge(LakePlacid,Plattsburgh), + edge(Plattsburgh,Massena), edge(LakePlacid,Massena), + edge(Massena,Watertown), edge(Watertown,Utica), + edge(Watertown,Syracuse), edge(Utica,Syracuse), + edge(Syracuse,Rochester), edge(Rochester,Buffalo), + edge(Syracuse,Ithaca), edge(Ithaca,Binghamton), + edge(Ithaca,Rochester), edge(Binghamton,Troy), + edge(Binghamton,Woodstock), edge(Binghamton,NewYork), + edge(Syracuse,Binghamton), edge(Woodstock,Troy), + edge(Woodstock,NewYork) + }; + unsigned int num_edges = sizeof(edge_array) / sizeof(edge); + cost weights[] = { // estimated travel time (mins) + 96, 134, 143, 65, 115, 133, 117, 116, 74, 56, + 84, 73, 69, 70, 116, 147, 173, 183, 74, 71, 124 + }; + + + // create graph + mygraph_t g(N); + WeightMap weightmap = get(edge_weight, g); + for(std::size_t j = 0; j < num_edges; ++j) { + edge_descriptor e; bool inserted; + tie(e, inserted) = add_edge(edge_array[j].first, + edge_array[j].second, g); + weightmap[e] = weights[j]; + } + + + // pick random start/goal + mt19937 gen(time(0)); + vertex start = random_vertex(g, gen); + vertex goal = random_vertex(g, gen); + + + cout << "Start vertex: " << name[start] << endl; + cout << "Goal vertex: " << name[goal] << endl; + + vector p(num_vertices(g)); + vector d(num_vertices(g)); + try { + // call astar named parameter interface + astar_search + (g, start, + distance_heuristic + (locations, goal), + predecessor_map(&p[0]).distance_map(&d[0]). + visitor(astar_goal_visitor(goal))); + + + } catch(found_goal fg) { // found a path to the goal + list shortest_path; + for(vertex v = goal;; v = p[v]) { + shortest_path.push_front(v); + if(p[v] == v) + break; + } + cout << "Shortest path from " << name[start] << " to " + << name[goal] << ": "; + list::iterator spi = shortest_path.begin(); + cout << name[start]; + for(++spi; spi != shortest_path.end(); ++spi) + cout << " -> " << name[*spi]; + cout << endl << "Total travel time: " << d[goal] << endl; + return 0; + } + + cout << "Didn't find a path from " << name[start] << "to" + << name[goal] << "!" << endl; + return 0; + +} diff --git a/test/floyd_warshall_test.cpp b/test/floyd_warshall_test.cpp new file mode 100644 index 00000000..dbe8ca7b --- /dev/null +++ b/test/floyd_warshall_test.cpp @@ -0,0 +1,394 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +template +struct inf_plus{ + T operator()(const T& a, const T& b) const { + T inf = std::numeric_limits::max(); + if (a == inf || b == inf){ + return inf; + } + return a + b; + } +}; + + +template +bool acceptance_test(Graph& g, int vec, int e) +{ + boost::minstd_rand ran(vec); + + { + typename boost::property_map::type index = + boost::get(boost::vertex_name, g); + typename boost::graph_traits::vertex_iterator firstv, lastv, + firstv2, lastv2; + int x = 0; + for(boost::tie(firstv, lastv) = boost::vertices(g); firstv != lastv; + firstv++){ + boost::put(index, *firstv, x); + x++; + } + + + for(int i = 0; i < e; i++){ + boost::add_edge(index[ran() % vec], index[ran() % vec], g); + } + + + typename boost::graph_traits::edge_iterator first, last; + typename boost::property_map::type + local_edge_map = boost::get(boost::edge_weight, g); + for(boost::tie(first, last) = boost::edges(g); first != last; first++){ + if (ran() % vec != 0){ + boost::put(local_edge_map, *first, ran() % 100); + } else { + boost::put(local_edge_map, *first, 0 - (ran() % 100)); + } + } + + + typedef typename boost::graph_traits::vertex_descriptor vertex_des; + std::map matrixRow; + std::map > matrix; + typedef typename boost::property_map::type + distance_type; + distance_type distance_row = boost::get(boost::vertex_distance, g); + for(boost::tie(firstv, lastv) = boost::vertices(g); firstv != lastv; + firstv++){ + boost::put(distance_row, *firstv, std::numeric_limits::max()); + matrixRow[*firstv] = std::numeric_limits::max(); + } + for(boost::tie(firstv, lastv) = boost::vertices(g); firstv != lastv; + firstv++){ + matrix[*firstv] = matrixRow; + } + for(boost::tie(firstv, lastv) = boost::vertices(g); firstv != lastv; + firstv++){ + matrix[*firstv][*firstv] = 0; + } + std::map > matrix3(matrix); + std::map > matrix4(matrix); + for(boost::tie(first, last) = boost::edges(g); first != last; first++){ + if (matrix[boost::source(*first, g)][boost::target(*first, g)] + != std::numeric_limits::max()){ + matrix[boost::source(*first, g)][boost::target(*first, g)] = + std::min(boost::get(local_edge_map, *first), + matrix[boost::source(*first, g)][boost::target(*first, g)]); + } else { + matrix[boost::source(*first, g)][boost::target(*first, g)] = + boost::get(local_edge_map, *first); + } + } + bool is_undirected = + boost::is_same::directed_category, + boost::undirected_tag>::value; + if (is_undirected){ + for(boost::tie(first, last) = boost::edges(g); first != last; first++){ + if (matrix[boost::target(*first, g)][boost::source(*first, g)] + != std::numeric_limits::max()){ + matrix[boost::target(*first, g)][boost::source(*first, g)] = + std::min(boost::get(local_edge_map, *first), + matrix[boost::target(*first, g)][boost::source(*first, g)]); + } else { + matrix[boost::target(*first, g)][boost::source(*first, g)] = + boost::get(local_edge_map, *first); + } + } + } + + + bool bellman, floyd1, floyd2, floyd3; + std::less compare; + inf_plus combine; + floyd1 = + boost::floyd_warshall_initialized_all_pairs_shortest_paths + (g, + matrix, weight_map(boost::get(boost::edge_weight, g)). + distance_compare(compare). distance_combine(combine). + distance_inf(std::numeric_limits::max()). distance_zero(0)); + + floyd2 = + boost::floyd_warshall_all_pairs_shortest_paths + (g, matrix3, + weight_map(local_edge_map). distance_compare(compare). + distance_combine(combine). + distance_inf(std::numeric_limits::max()). distance_zero(0)); + + floyd3 = boost::floyd_warshall_all_pairs_shortest_paths(g, matrix4); + + + boost::dummy_property_map dummy_map; + std::map > matrix2; + for(boost::tie(firstv, lastv) = vertices(g); firstv != lastv; firstv++){ + boost::put(distance_row, *firstv, 0); + bellman = + boost::bellman_ford_shortest_paths + (g, vec, + weight_map(boost::get(boost::edge_weight, g)). + distance_map(boost::get(boost::vertex_distance, g)). + predecessor_map(dummy_map).distance_compare(compare). + distance_combine(combine)); + distance_row = boost::get(boost::vertex_distance, g); + for(boost::tie(firstv2, lastv2) = vertices(g); firstv2 != lastv2; + firstv2++){ + matrix2[*firstv][*firstv2] = boost::get(distance_row, *firstv2); + boost::put(distance_row, *firstv2, std::numeric_limits::max()); + } + if(bellman == false){ + break; + } + } + + + if (bellman != floyd1 || bellman != floyd2 || bellman != floyd3){ + std::cout << + "A negative cycle was detected in one algorithm but not the others. " + << std::endl; + return false; + } + else if (bellman == false && floyd1 == false && floyd2 == false && + floyd3 == false){ + return true; + } + else { + typename boost::graph_traits::vertex_iterator first1, first2, + last1, last2; + for (boost::tie(first1, last1) = boost::vertices(g); first1 != last1; + first1++){ + for (boost::tie(first2, last2) = boost::vertices(g); first2 != last2; + first2++){ + if (matrix2[*first1][*first2] != matrix[*first1][*first2]){ + std::cout << "Algorithms do not match at matrix point " + << index[*first1] << " " << index[*first2] + << " Bellman results: " << matrix2[*first1][*first2] + << " floyd 1 results " << matrix[*first1][*first2] + << std::endl; + return false; + } + if (matrix2[*first1][*first2] != matrix3[*first1][*first2]){ + std::cout << "Algorithms do not match at matrix point " + << index[*first1] << " " << index[*first2] + << " Bellman results: " << matrix2[*first1][*first2] + << " floyd 2 results " << matrix3[*first1][*first2] + << std::endl; + return false; + } + if (matrix2[*first1][*first2] != matrix4[*first1][*first2]){ + std::cout << "Algorithms do not match at matrix point " + << index[*first1] << " " << index[*first2] + << " Bellman results: " << matrix2[*first1][*first2] + << " floyd 3 results " << matrix4[*first1][*first2] + << std::endl; + return false; + } + } + } + } + + } + return true; +} + +template +bool acceptance_test2(Graph& g, int vec, int e) +{ + boost::minstd_rand ran(vec); + + { + + typename boost::property_map::type index = + boost::get(boost::vertex_name, g); + typename boost::graph_traits::vertex_iterator firstv, lastv, + firstv2, lastv2; + int x = 0; + for(boost::tie(firstv, lastv) = boost::vertices(g); firstv != lastv; + firstv++){ + boost::put(index, *firstv, x); + x++; + } + + boost::generate_random_graph(g, vec, e, ran, true); + + typename boost::graph_traits::edge_iterator first, last; + typename boost::property_map::type + local_edge_map = boost::get(boost::edge_weight, g); + for(boost::tie(first, last) = boost::edges(g); first != last; first++){ + if (ran() % vec != 0){ + boost::put(local_edge_map, *first, ran() % 100); + } else { + boost::put(local_edge_map, *first, 0 - (ran() % 100)); + } + } + + + typedef typename boost::graph_traits::vertex_descriptor vertex_des; + std::map matrixRow; + std::map > matrix; + typedef typename boost::property_map::type + distance_type; + distance_type distance_row = boost::get(boost::vertex_distance, g); + for(boost::tie(firstv, lastv) = boost::vertices(g); firstv != lastv; + firstv++){ + boost::put(distance_row, *firstv, std::numeric_limits::max()); + matrixRow[*firstv] = std::numeric_limits::max(); + } + for(boost::tie(firstv, lastv) = boost::vertices(g); firstv != lastv; + firstv++){ + matrix[*firstv] = matrixRow; + } + for(boost::tie(firstv, lastv) = boost::vertices(g); firstv != lastv; + firstv++){ + matrix[*firstv][*firstv] = 0; + } + std::map > matrix3(matrix); + std::map > matrix4(matrix); + for(boost::tie(first, last) = boost::edges(g); first != last; first++){ + if (matrix[boost::source(*first, g)][boost::target(*first, g)] + != std::numeric_limits::max()){ + matrix[boost::source(*first, g)][boost::target(*first, g)] = + std::min(boost::get(local_edge_map, *first), + matrix[boost::source(*first, g)][boost::target(*first, g)]); + } else { + matrix[boost::source(*first, g)][boost::target(*first, g)] = + boost::get(local_edge_map, *first); + } + } + bool is_undirected = + boost::is_same::directed_category, + boost::undirected_tag>::value; + if (is_undirected){ + for(boost::tie(first, last) = boost::edges(g); first != last; first++){ + if (matrix[boost::target(*first, g)][boost::source(*first, g)] + != std::numeric_limits::max()){ + matrix[boost::target(*first, g)][boost::source(*first, g)] = + std::min(boost::get(local_edge_map, *first), + matrix[boost::target(*first, g)][boost::source(*first, g)]); + } else { + matrix[boost::target(*first, g)][boost::source(*first, g)] = + boost::get(local_edge_map, *first); + } + } + } + + + bool bellman, floyd1, floyd2, floyd3; + std::less compare; + inf_plus combine; + floyd1 = + boost::floyd_warshall_initialized_all_pairs_shortest_paths + (g, + matrix, weight_map(boost::get(boost::edge_weight, g)). + distance_compare(compare). distance_combine(combine). + distance_inf(std::numeric_limits::max()). distance_zero(0)); + + floyd2 = + boost::floyd_warshall_all_pairs_shortest_paths + (g, matrix3, + weight_map(local_edge_map). distance_compare(compare). + distance_combine(combine). + distance_inf(std::numeric_limits::max()). distance_zero(0)); + + floyd3 = boost::floyd_warshall_all_pairs_shortest_paths(g, matrix4); + + + boost::dummy_property_map dummy_map; + std::map > matrix2; + for(boost::tie(firstv, lastv) = vertices(g); firstv != lastv; firstv++){ + boost::put(distance_row, *firstv, 0); + bellman = + boost::bellman_ford_shortest_paths + (g, vec, + weight_map(boost::get(boost::edge_weight, g)). + distance_map(boost::get(boost::vertex_distance, g)). + predecessor_map(dummy_map).distance_compare(compare). + distance_combine(combine)); + distance_row = boost::get(boost::vertex_distance, g); + for(boost::tie(firstv2, lastv2) = vertices(g); firstv2 != lastv2; + firstv2++){ + matrix2[*firstv][*firstv2] = boost::get(distance_row, *firstv2); + boost::put(distance_row, *firstv2, std::numeric_limits::max()); + } + if(bellman == false){ + break; + } + } + + + if (bellman != floyd1 || bellman != floyd2 || bellman != floyd3){ + std::cout << + "A negative cycle was detected in one algorithm but not the others. " + << std::endl; + return false; + } + else if (bellman == false && floyd1 == false && floyd2 == false && + floyd3 == false){ + return true; + } + else { + typename boost::graph_traits::vertex_iterator first1, first2, + last1, last2; + for (boost::tie(first1, last1) = boost::vertices(g); first1 != last1; + first1++){ + for (boost::tie(first2, last2) = boost::vertices(g); first2 != last2; + first2++){ + if (matrix2[*first1][*first2] != matrix[*first1][*first2]){ + std::cout << "Algorithms do not match at matrix point " + << index[*first1] << " " << index[*first2] + << " Bellman results: " << matrix2[*first1][*first2] + << " floyd 1 results " << matrix[*first1][*first2] + << std::endl; + return false; + } + if (matrix2[*first1][*first2] != matrix3[*first1][*first2]){ + std::cout << "Algorithms do not match at matrix point " + << index[*first1] << " " << index[*first2] + << " Bellman results: " << matrix2[*first1][*first2] + << " floyd 2 results " << matrix3[*first1][*first2] + << std::endl; + return false; + } + if (matrix2[*first1][*first2] != matrix4[*first1][*first2]){ + std::cout << "Algorithms do not match at matrix point " + << index[*first1] << " " << index[*first2] + << " Bellman results: " << matrix2[*first1][*first2] + << " floyd 3 results " << matrix4[*first1][*first2] + << std::endl; + return false; + } + } + } + } + + } + return true; +} + +int test_main(int, char*[]) +{ + typedef boost::adjacency_list > , + boost::property > Digraph; + Digraph adjlist_digraph; + BOOST_TEST(acceptance_test2(adjlist_digraph, 100, 2000)); + + typedef boost::adjacency_matrix > , + boost::property > Graph; + Graph matrix_graph(100); + BOOST_TEST(acceptance_test(matrix_graph, 100, 2000)); + + return 0; +} diff --git a/test/layout_test.cpp b/test/layout_test.cpp index 404b25b0..1969c8f8 100644 --- a/test/layout_test.cpp +++ b/test/layout_test.cpp @@ -6,9 +6,12 @@ // Authors: Douglas Gregor // Andrew Lumsdaine +#include +#include #include #include #include +#include #include #include #include @@ -149,7 +152,7 @@ test_triangle(Graph*) side_length(50.0)); BOOST_TEST(ok); - std::cout << "Triangle layout.\n"; + std::cout << "Triangle layout (Kamada-Kawai).\n"; print_graph_layout(g, get(vertex_position, g)); } @@ -191,10 +194,32 @@ test_cube(Graph*) kamada_kawai_done()); BOOST_TEST(ok); - std::cout << "Cube layout.\n"; + std::cout << "Cube layout (Kamada-Kawai).\n"; print_graph_layout(g, get(vertex_position, g)); dump_graph_layout("cube", g, get(vertex_position, g)); + + minstd_rand gen; + random_graph_layout(g, get(vertex_position, g), -25.0, 25.0, -25.0, 25.0, + gen); + + std::vector displacements(num_vertices(g)); + fruchterman_reingold_force_directed_layout + (g, + get(vertex_position, g), + 50.0, + 50.0, + square_distance_attractive_force(), + square_distance_repulsive_force(), + all_force_pairs(), + linear_cooling(100), + make_iterator_property_map(displacements.begin(), + get(vertex_index, g))); + + std::cout << "Cube layout (Fruchterman-Reingold).\n"; + print_graph_layout(g, get(vertex_position, g)); + + dump_graph_layout("cube-fr", g, get(vertex_position, g)); } template @@ -235,10 +260,88 @@ test_triangular(Graph*) kamada_kawai_done()); BOOST_TEST(ok); - std::cout << "Triangular layout.\n"; + std::cout << "Triangular layout (Kamada-Kawai).\n"; print_graph_layout(g, get(vertex_position, g)); - dump_graph_layout("triangular", g, get(vertex_position, g)); + dump_graph_layout("triangular-kk", g, get(vertex_position, g)); + + minstd_rand gen; + random_graph_layout(g, get(vertex_position, g), -25.0, 25.0, -25.0, 25.0, + gen); + + dump_graph_layout("random", g, get(vertex_position, g)); + + std::vector displacements(num_vertices(g)); + fruchterman_reingold_force_directed_layout + (g, + get(vertex_position, g), + 50.0, + 50.0, + attractive_force(square_distance_attractive_force()). + cooling(linear_cooling(100))); + + std::cout << "Triangular layout (Fruchterman-Reingold).\n"; + print_graph_layout(g, get(vertex_position, g)); + + dump_graph_layout("triangular-fr", g, get(vertex_position, g)); +} + +template +void +test_disconnected(Graph*) +{ + enum {A, B, C, D, E, F, G, H}; + simple_edge triangular_edges[13] = { + {A, B}, {B, C}, {C, A}, + {D, E}, {E, F}, {F, G}, {G, H}, {H, D}, + {D, F}, {F, H}, {H, E}, {E, G}, {G, D} + }; + + Graph g(&triangular_edges[0], &triangular_edges[13], 8); + + typedef typename graph_traits::edge_iterator edge_iterator; + typedef typename graph_traits::vertex_iterator vertex_iterator; + + vertex_iterator vi, vi_end; + int i = 0; + for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi) + put(vertex_index, g, *vi, i++); + + edge_iterator ei, ei_end; + for (tie(ei, ei_end) = edges(g); ei != ei_end; ++ei) { + put(edge_weight, g, *ei, 1.0); + std::cerr << "(" << (char)(get(vertex_index, g, source(*ei, g)) + 'A') + << ", " << (char)(get(vertex_index, g, target(*ei, g)) + 'A') + << ") "; + } + std::cerr << std::endl; + + circle_graph_layout(g, get(vertex_position, g), 25.0); + + bool ok = kamada_kawai_spring_layout(g, + get(vertex_position, g), + get(edge_weight, g), + side_length(50.0), + kamada_kawai_done()); + BOOST_TEST(!ok); + + minstd_rand gen; + random_graph_layout(g, get(vertex_position, g), -25.0, 25.0, -25.0, 25.0, + gen); + + std::vector displacements(num_vertices(g)); + fruchterman_reingold_force_directed_layout + (g, + get(vertex_position, g), + 50.0, + 50.0, + attractive_force(square_distance_attractive_force()). + cooling(linear_cooling(50))); + + std::cout << "Disconnected layout (Fruchterman-Reingold).\n"; + print_graph_layout(g, get(vertex_position, g)); + + dump_graph_layout("disconnected-fr", g, get(vertex_position, g)); } int test_main(int, char*[]) @@ -253,6 +356,6 @@ int test_main(int, char*[]) test_circle_layout((Graph*)0, 5); test_cube((Graph*)0); test_triangular((Graph*)0); - + test_disconnected((Graph*)0); return 0; }