2009-02-23 Jb Evain <jbevain@novell.com>
[mcs.git] / class / Mono.C5 / UserGuideExamples / Graph.cs
blob661b4caecdd732bf4e7bd55bd47b6bbf1aadb52c
1 /*
2 Copyright (c) 2003-2006 Niels Kokholm and Peter Sestoft
3 Permission is hereby granted, free of charge, to any person obtaining a copy
4 of this software and associated documentation files (the "Software"), to deal
5 in the Software without restriction, including without limitation the rights
6 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 copies of the Software, and to permit persons to whom the Software is
8 furnished to do so, subject to the following conditions:
10 The above copyright notice and this permission notice shall be included in
11 all copies or substantial portions of the Software.
13 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 SOFTWARE.
22 // C5 example: Graph representation with basic algorithms using C5
25 // Compile with
26 // csc /r:C5.dll Graph.cs
29 // The code is structured as a rudimentary Graph library, with an interface
30 // for (edge)weighted graphs and a single implementation based on an
31 // adjacency list representation using hash dictionaries.
34 // The algorithms implemented include:
36 // Breadth-First-Search and Depth-First-Search, with an interface based on actions
37 // to be taken as edges are traversed. Applications are checking for connectedness,
38 // counting components
40 // Priority-First-Search, where edges are traversed according to either weight or
41 // accumulated weight from the start of the search.
42 // An application of the non-accumulating version is the construction of a minimal
43 // spanning tree and therefore the following approximation algorithm.
44 // Applications of the accumulating version are the construction of a shortest path
45 // and the computation of the distance from one vertex to another one.
47 // An approximation algorithm for Travelling Salesman Problems,
48 // where the weights satisfies the triangle inequality.
51 // Pervasive generic parameters:
52 // V: The type of a vertex in a graph. Vertices are identified
53 // by the Equals method inherited from object (or overridden).
54 // E: The type of additional data associated with edges in a graph.
55 // W: The type of values of weights on edges in a weighted graph,
56 // in practise usually int or double. Must be comparable and
57 // there must be given a compatible way to add values.
59 // Interfaces:
60 // IGraph<V,E,W>: The interface for a graph implementation with
61 // vertex type V, edge dat type E and weight values of type W.
62 // IWeight<E,W>: The interface of a weight function
64 // Classes:
65 // HashGraph<V,E,W>: An implementation of IWeightedGraph<V,E,W> based on
66 // adjacency lists represented as hash dictionaries.
67 // HashGraph<V,E,W>.EdgesValue: A helper class for the Edges() method
68 // CountWeight<E>: A
69 // IntWeight:
70 // DoubleWeight:
72 // Value Types:
73 // Edge<V,E>:
74 // EdgeAction<V,E,U>:
76 // Some notes:
77 // The code only supports "natural" equality of vertices.
79 using C5;
80 using System;
81 using SCG = System.Collections.Generic;
83 namespace Graph
85 /// <summary>
86 /// (Duer ikke)
87 /// </summary>
88 /// <typeparam name="V"></typeparam>
89 /// <typeparam name="E"></typeparam>
90 interface IGraphVertex<V, E,W> where W : IComparable<W>
92 V Value { get;}
93 IGraph<V, E, W> Graph { get;}
94 ICollectionValue<KeyValuePair<V, E>> Adjacent { get;}
98 class Vertex<V>
100 //V v;
102 /// <summary>
103 ///
104 /// </summary>
105 /// <typeparam name="V"></typeparam>
106 /// <typeparam name="E"></typeparam>
107 /// <typeparam name="W"></typeparam>
108 interface IGraph<V, E, W> where W : IComparable<W>
110 /// <summary>
111 ///
112 /// </summary>
113 /// <value>The weight object for this graph</value>
114 IWeight<E, W> Weight { get;}
116 /// <summary>
117 ///
118 /// </summary>
119 /// <value>The number of vertices in this graph</value>
120 int VertexCount { get;}
122 /// <summary>
123 ///
124 /// </summary>
125 /// <value>The number of edges in this graph</value>
126 int EdgeCount { get;}
128 /// <summary>
129 /// The collection of vertices of this graph.
130 /// The return value is a snapshot, not a live view onto the graph.
131 /// </summary>
132 /// <returns></returns>
133 ICollectionValue<V> Vertices();
135 /// <summary>
136 /// The collection of edges incident to a particular vertex.
137 /// The return value is a snapshot og (endvertex, edgedata) pairs.
138 /// </summary>
139 /// <param name="vertex"></param>
140 /// <returns></returns>
141 ICollectionValue<KeyValuePair<V, E>> Adjacent(V vertex);
143 /// <summary>
144 /// The collection of all edges in the graph. The return value is a snapshot
145 /// of Edge values. Each edge is present once for an undefined direction.
146 /// </summary>
147 /// <returns></returns>
148 ICollectionValue<Edge<V, E>> Edges();
150 /// <summary>
151 /// Add a(n isolated) vertex to the graph Ignore if vertex is already in the graph.
152 /// </summary>
153 /// <param name="vertex"></param>
154 /// <returns>True if the vertex was added.</returns>
155 bool AddVertex(V vertex);
157 /// <summary>
158 /// Add an edge to the graph. If the edge is already in the graph, update the
159 /// edge data. Add vertices as needed.
160 /// </summary>
161 /// <param name="start"></param>
162 /// <param name="end"></param>
163 /// <param name="edgedata"></param>
164 /// <returns>True if the edge was added</returns>
165 bool AddEdge(V start, V end, E edgedata);
167 /// <summary>
168 /// Remove a vertex and all its incident edges from the graph.
169 /// </summary>
170 /// <returns>True if the vertex was already in the graph and hence was removed</returns>
171 bool RemoveVertex(V vertex);
173 /// <summary>
174 /// Remove an edge from the graph. Do not remove the vertices if they become isolated.
175 /// </summary>
176 /// <param name="start"></param>
177 /// <param name="end"></param>
178 /// <param name="edgedata">On output, the edge data associated with the removed edge.</param>
179 /// <returns>True if </returns>
180 bool RemoveEdge(V start, V end, out E edgedata);
182 /// <summary>
183 /// Is there an edge from start to end in this graph, and if so, what is
184 /// the data on that edge.
185 /// </summary>
186 /// <param name="start"></param>
187 /// <param name="end"></param>
188 /// <param name="edge"></param>
189 /// <returns></returns>
190 bool FindEdge(V start, V end, out E edge);
192 /// <summary>
193 /// Construct the subgraph corresponding to a set of vertices.
194 /// </summary>
195 /// <param name="vs"></param>
196 /// <returns></returns>
197 IGraph<V, E, W> SubGraph(ICollectionValue<V> vs);
199 /// <summary>
200 ///
201 /// </summary>
202 /// <value>True if graph is connected</value>
203 bool IsConnected { get; }
205 /// <summary>
206 ///
207 /// </summary>
208 /// <value>The number of connected components of this graph</value>
209 int ComponentCount { get;}
211 /// <summary>
212 /// Compute the connnected components of this graph.
213 /// </summary>
214 /// <returns>A collection of (vertex,component) pairs, where the first part of the
215 /// pair is some vertex in the component.</returns>
216 ICollectionValue<KeyValuePair<V, IGraph<V, E, W>>> Components();
218 /// <summary>
219 /// Traverse the connected component containing the <code>start</code> vertex,
220 /// in either BFS or DFS order, beginning at <code>start</code> and performing the action
221 /// <code>act</code> on each edge part of the constructed tree.
222 /// </summary>
223 /// <param name="bfs">True if BFS, false if DFS</param>
224 /// <param name="start">The vertex to start at</param>
225 /// <param name="act">The action to perform at each node</param>
226 void TraverseVertices(bool bfs, V start, Action<Edge<V, E>> act);
228 /// <summary>
229 /// Traverse an undirected graph in either BFS or DFS order, performing the action
230 /// <code>act</code> on each vertex.
231 /// The start vertex of each component of the graph is undefinded.
232 /// </summary>
233 /// <param name="bfs">True if BFS, false if DFS</param>
234 /// <param name="act"></param>
235 void TraverseVertices(bool bfs, Action<V> act);
237 /// <summary>
238 /// Traverse an undirected graph in either BFS or DFS order, performing the action
239 /// <code>act</code> on each edge in the traversal and beforecomponent/aftercomponent
240 /// at the start and end of each component (with argument: the start vertex of the component).
241 /// </summary>
242 /// <param name="bfs">True if BFS, false if DFS</param>
243 /// <param name="act"></param>
244 /// <param name="beforecomponent"></param>
245 /// <param name="aftercomponent"></param>
246 void TraverseVertices(bool bfs, Action<Edge<V, E>> act, Action<V> beforecomponent, Action<V> aftercomponent);
248 /// <summary>
249 /// A more advanced Depth First Search traversal.
250 /// </summary>
251 /// <param name="start">The vertex to start the search at</param>
252 /// <param name="beforevertex">Action to perform when a vertex is first encountered.</param>
253 /// <param name="aftervertex">Action to perform when all edges out of a vertex has been handles.</param>
254 /// <param name="onfollow">Action to perform as an edge is traversed.</param>
255 /// <param name="onfollowed">Action to perform when an edge is travesed back.</param>
256 /// <param name="onnotfollowed">Action to perform when an edge (a backedge)is seen, but not followed.</param>
257 void DepthFirstSearch(V start, Action<V> beforevertex, Action<V> aftervertex,
258 Action<Edge<V, E>> onfollow, Action<Edge<V, E>> onfollowed, Action<Edge<V, E>> onnotfollowed);
260 //TODO: perhaps we should avoid exporting this?
261 /// <summary>
262 /// Traverse the part of the graph reachable from start in order of least distance
263 /// from start according to the weight function. Perform act on the edges of the
264 /// traversal as they are recognised.
265 /// </summary>
266 /// <typeparam name="W"></typeparam>
267 /// <param name="weight"></param>
268 /// <param name="start"></param>
269 /// <param name="act"></param>
270 void PriorityFirstTraverse(bool accumulating, V start, EdgeAction<V, E, W> act);
272 /// <summary>
273 /// Compute the (a) shortest path from start to end. THrow an exception if end cannot be reached rom start.
274 /// </summary>
275 /// <param name="weight"></param>
276 /// <param name="start"></param>
277 /// <param name="end"></param>
278 /// <returns></returns>
279 ICollectionValue<Edge<V, E>> ShortestPath(V start, V end);
281 /// <summary>
282 /// Compute the Distance from start to end, i.e. the total weight of a shortest path from start to end.
283 /// Throw an exception if end cannot be reached rom start.
284 /// </summary>
285 /// <param name="start"></param>
286 /// <param name="end"></param>
287 /// <returns></returns>
288 W Distance(V start, V end);
290 /// <summary>
291 /// Compute a minimum spanning tree for the graph.
292 /// Throw an exception if this graph is not connected.
293 /// </summary>
294 /// <param name="root">(The starting point of the PFS, to be removed)</param>
295 /// <returns></returns>
296 IGraph<V, E, W> MinimumSpanningTree(out V root);
298 /// <summary>
299 /// Compute a factor 2 approximation to a Minimum Weight
300 /// Perfect Matching in a graph using NNs
301 /// </summary>
302 /// <returns></returns>
303 ICollectionValue<Edge<V, E>> ApproximateMWPM();
305 /// <summary>
306 /// Construct a closed Euler tour of this graph if one exists, i.e. if
307 /// the graph is connected and all vertices have even degrees. Throw an
308 /// ArgumentException if no closed Euler tour exists.
309 /// </summary>
310 /// <returns>A list of vertices in an Euler tour of this graph.</returns>
311 IList<V> EulerTour();
313 /// <summary>
314 /// This is intended for implementations of the very simple factor 2 approximation
315 /// algorithms for the travelling salesman problem for Euclidic weight/distance
316 /// functions, i.e. distances that satisfy the triangle inequality. (We do not do 3/2)
317 /// </summary>
318 /// <returns></returns>
319 IDirectedCollectionValue<V> ApproximateTSP();
321 /// <summary>
322 /// Pretty-print the graph to the console (for debugging purposes).
323 /// </summary>
324 void Print(System.IO.TextWriter output);
327 /// <summary>
328 /// The type of an edge in a graph. An edge is identified by its pair of
329 /// vertices. The pair is considered ordered, and so an Edge really describes
330 /// an edge of the graph in a particular traversal direction.
331 /// </summary>
332 /// <typeparam name="V">The type of a vertex.</typeparam>
333 /// <typeparam name="E">The type of data asociated with edges.</typeparam>
334 struct Edge<V, E>
336 static SCG.IEqualityComparer<V> vequalityComparer = EqualityComparer<V>.Default;
337 public readonly V start, end;
338 public readonly E edgedata;
339 public Edge(V start, V end, E edgedata)
341 if (vequalityComparer.Equals(start, end))
342 throw new ArgumentException("Illegal: start and end are equal");
343 this.start = start; this.end = end; this.edgedata = edgedata;
346 public Edge<V, E> Reverse()
348 return new Edge<V, E>(end, start, edgedata);
351 public override string ToString()
353 return String.Format("(start='{0}', end='{1}', edgedata='{2}')", start, end, edgedata); ;
356 public override bool Equals(object obj)
358 if (obj is Edge<V, E>)
360 Edge<V, E> other = (Edge<V, E>)obj;
361 return vequalityComparer.Equals(start, other.start) && vequalityComparer.Equals(end, other.end);
363 return false;
366 /// <summary>
367 ///
368 /// </summary>
369 /// <returns></returns>
370 public override int GetHashCode()
372 //TODO: should we use xor? Or a random factor?
373 return start.GetHashCode() + 148712671 * end.GetHashCode();
376 /// <summary>
377 /// The unordered equalityComparer compares edges independent of the order of the vertices.
378 /// </summary>
379 public class UnorderedEqualityComparer : SCG.IEqualityComparer<Edge<V, E>>
381 /// <summary>
382 /// Check if two edges have the same vertices irrespective of order.
383 /// </summary>
384 /// <param name="i1"></param>
385 /// <param name="i2"></param>
386 /// <returns></returns>
387 public bool Equals(Edge<V, E> i1, Edge<V, E> i2)
389 return (vequalityComparer.Equals(i1.start, i2.start) && vequalityComparer.Equals(i1.end, i2.end)) ||
390 (vequalityComparer.Equals(i1.end, i2.start) && vequalityComparer.Equals(i1.start, i2.end));
393 /// <summary>
394 /// Return a hash code compatible with the unordered equals.
395 /// </summary>
396 /// <param name="item"></param>
397 /// <returns></returns>
398 public int GetHashCode(Edge<V, E> item)
400 return item.start.GetHashCode() ^ item.end.GetHashCode();
405 /// <summary>
406 /// The type of the weight object of a graph. This consists of a function mapping
407 /// edge data values to weight values, and an operation to add two weight values.
408 /// It is required that weight values are comparable.
409 ///
410 /// The user must assure that the add operation is commutative and fulfills
411 /// Add(w1,w2) &le; w1 for all w1 and w2 that can appear as weights or sums of
412 /// weights. In practise, W will be int or double, all weight values will be
413 /// non-negative and the addition will be the natural addition on W.
414 /// </summary>
415 /// <typeparam name="E"></typeparam>
416 /// <typeparam name="W"></typeparam>
417 interface IWeight<E, W> where W : IComparable<W>
419 /// <summary>
420 /// Compute the weight value corresponding to specific edge data.
421 /// </summary>
422 /// <param name="edgedata"></param>
423 /// <returns></returns>
424 W Weight(E edgedata);
426 /// <summary>
427 /// Add two weight values.
428 /// </summary>
429 /// <param name="w1"></param>
430 /// <param name="w2"></param>
431 /// <returns></returns>
432 W Add(W w1, W w2);
435 /// <summary>
436 /// An action to perform when an edge is encountered during a traversal of the graph.
437 /// The "extra" parameter is for additional information supplied by the traversal
438 /// algorithm.
439 /// The intention of the bool return value is that returning false is a signal to the
440 /// traversal algorithm to abandon the traversl because the user has already found
441 /// what he was looking for.
442 /// </summary>
443 /// <typeparam name="V"></typeparam>
444 /// <typeparam name="E"></typeparam>
445 /// <typeparam name="U"></typeparam>
446 /// <param name="edge"></param>
447 /// <param name="extra"></param>
448 /// <returns></returns>
449 delegate bool EdgeAction<V, E, U>(Edge<V, E> edge, U extra);
453 For a dense graph, we would use data fields:
455 E'[,] or E'[][] for the matrix. Possibly E'[][] for a triangular one!
456 Here E' = struct{E edgedata, bool present} or class{E edgedata}, or if E is a class just E.
457 Thus E' is E! for value types. Or we could have two matrices: E[][] and bool[][].
459 HashDictionary<V,int> to map vertex ids to indices.
460 ArrayList<V> for the map the other way.
461 Or simply a HashedArrayList<V> to get both?
463 PresentList<int>, FreeList<int> or similar, if we do not want to compact the indices in the matrix on each delete.
464 If we compact, we always do a delete on the vertex<->index map by a replace and a removelast:
465 vimap[ind]=vimap[vimap.Count]; vimap.RemoveLast(); //also reorder matrix!
470 /// <summary>
471 /// An implementation of IGraph&le;V,E,W&ge; based on an adjacency list representation using hash dictionaries.
472 /// As a consequence, this will be most efficient for sparse graphs.
473 /// </summary>
474 /// <typeparam name="V"></typeparam>
475 /// <typeparam name="E"></typeparam>
476 /// <typeparam name="W"></typeparam>
477 class HashGraph<V, E, W> : IGraph<V, E, W> where W : IComparable<W>
479 int edgecount;
481 HashDictionary<V, HashDictionary<V, E>> graph;
483 IWeight<E, W> weight;
485 public IWeight<E, W> Weight { get { return weight; } }
488 /// <summary>
489 /// Create an initially empty graph.
490 /// </summary>
491 /// <param name="weight"></param>
492 [UsedBy("testTSP")]
493 public HashGraph(IWeight<E, W> weight)
495 this.weight = weight;
496 edgecount = 0;
497 graph = new HashDictionary<V, HashDictionary<V, E>>();
500 /// <summary>
501 /// Constructing a graph with no isolated vertices given a collection of edges.
502 /// </summary>
503 /// <param name="edges"></param>
504 [UsedBy()]
505 public HashGraph(IWeight<E, W> weight, SCG.IEnumerable<Edge<V, E>> edges) : this(weight)
507 foreach (Edge<V, E> edge in edges)
509 if (edge.start.Equals(edge.end))
510 throw new ApplicationException("Edge has equal start and end");
512 HashDictionary<V, E> edgeset;
513 //TODO: utilize upcoming FindOrAddSome operation
514 if (!graph.Find(edge.start, out edgeset))
515 graph.Add(edge.start, edgeset = new HashDictionary<V, E>());
516 if (!edgeset.UpdateOrAdd(edge.end, edge.edgedata))
517 edgecount++;
518 if (!graph.Find(edge.end, out edgeset))
519 graph.Add(edge.end, edgeset = new HashDictionary<V, E>());
520 edgeset.UpdateOrAdd(edge.start, edge.edgedata);
525 /// <summary>
526 /// This constructs a graph with a given set of vertices.
527 /// Will only allow these vertices.
528 /// Duplicate edges are allowed.
529 /// </summary>
530 /// <param name="vertices"></param>
531 /// <param name="edges"></param>
532 public HashGraph(IWeight<E, W> weight, SCG.IEnumerable<V> vertices, SCG.IEnumerable<Edge<V, E>> edges) : this(weight)
534 foreach (V v in vertices)
535 graph.Add(v, new HashDictionary<V, E>());
536 foreach (Edge<V, E> edge in edges)
538 HashDictionary<V, E> edgeset;
539 if (edge.start.Equals(edge.end))
540 throw new ApplicationException("Edge has equal start and end");
541 if (!graph.Find(edge.start, out edgeset))
542 throw new ApplicationException("Edge has unknown start");
543 if (!edgeset.UpdateOrAdd(edge.end, edge.edgedata))
544 edgecount++;
545 if (!graph.Find(edge.end, out edgeset))
546 throw new ApplicationException("Edge has unknown end");
547 edgeset.UpdateOrAdd(edge.start, edge.edgedata);
551 [UsedBy("testCOMP")]
552 public int VertexCount { get { return graph.Count; } }
554 [UsedBy("testCOMP")]
555 public int EdgeCount { get { return edgecount; } }
557 public ICollectionValue<V> Vertices()
559 return new GuardedCollectionValue<V>(graph.Keys);
562 public ICollectionValue<KeyValuePair<V, E>> Adjacent(V vertex)
564 return new GuardedCollectionValue<KeyValuePair<V, E>>(graph[vertex]);
567 class EdgesValue : CollectionValueBase<Edge<V, E>>
569 HashGraph<V, E, W> graph;
570 internal EdgesValue(HashGraph<V, E, W> g) { graph = g; }
572 public override bool IsEmpty { get { return graph.edgecount == 0; } }
574 public override int Count { get { return graph.edgecount; } }
576 public override Speed CountSpeed { get { return Speed.Constant; } }
579 public override Edge<V, E> Choose()
581 KeyValuePair<V, HashDictionary<V, E>> adjacent = graph.graph.Choose();
582 KeyValuePair<V, E> otherend = graph.graph[adjacent.Key].Choose();
583 return new Edge<V, E>(adjacent.Key, otherend.Key, otherend.Value);
586 public override SCG.IEnumerator<Edge<V, E>> GetEnumerator()
588 HashSet<Edge<V, E>> seen = new HashSet<Edge<V, E>>(new Edge<V, E>.UnorderedEqualityComparer());
589 foreach (V v in graph.graph.Keys)
590 foreach (KeyValuePair<V, E> p in graph.graph[v])
592 Edge<V, E> edge = new Edge<V, E>(v, p.Key, p.Value);
593 if (!seen.FindOrAdd(ref edge))
594 yield return edge;
599 public ICollectionValue<Edge<V, E>> Edges()
601 return new EdgesValue(this);
604 public bool AddVertex(V v)
606 if (graph.Contains(v))
607 return false;
608 graph.Add(v, new HashDictionary<V, E>());
609 return true;
612 //Note: no warning on update of edgedata!
613 //TODO: Shouldn't Update or Add return the old value?
614 //Then it would be easy to check for updates
615 public bool AddEdge(V start, V end, E edgedata)
617 bool retval = false;
618 HashDictionary<V, E> edgeset;
619 if (graph.Find(start, out edgeset))
620 retval = !edgeset.UpdateOrAdd(end, edgedata);
621 else
623 graph[start] = edgeset = new HashDictionary<V, E>();
624 edgeset[end] = edgedata;
625 retval = true;
627 if (graph.Find(end, out edgeset))
628 edgeset.UpdateOrAdd(start, edgedata);
629 else
631 graph[end] = edgeset = new HashDictionary<V, E>();
632 edgeset[start] = edgedata;
634 if (retval)
635 edgecount++;
636 return retval;
639 public bool RemoveVertex(V vertex)
641 HashDictionary<V, E> edgeset;
642 if (!graph.Find(vertex, out edgeset))
643 return false;
644 foreach (V othervertex in edgeset.Keys)
645 graph[othervertex].Remove(vertex); //Assert retval==true
646 edgecount -= edgeset.Count;
647 graph.Remove(vertex);
648 return true;
651 public bool RemoveEdge(V start, V end, out E edgedata)
653 HashDictionary<V, E> edgeset;
654 if (!graph.Find(start, out edgeset))
656 edgedata = default(E);
657 return false;
659 if (!edgeset.Remove(end, out edgedata))
660 return false;
661 graph[end].Remove(start);
662 edgecount--;
663 return true;
666 public bool FindEdge(V start, V end, out E edgedata)
668 HashDictionary<V, E> edges;
669 if (!graph.Find(start, out edges))
671 edgedata = default(E);
672 return false;
674 return edges.Find(end, out edgedata);
677 public IGraph<V, E, W> SubGraph(ICollectionValue<V> vs)
679 HashSet<V> vertexset = vs as HashSet<V>;
680 if (vertexset == null)
682 vertexset = new HashSet<V>();
683 vertexset.AddAll(vs);
686 return new HashGraph<V, E, W>(weight,
688 Edges().Filter(delegate(Edge<V, E> e) { return vertexset.Contains(e.start) && vertexset.Contains(e.end); }));
691 public bool IsConnected
693 //TODO: optimize: needs to change Action<Edge<V,E>> to EdgeAction to be able to break out
694 get { return ComponentCount <= 1; }
697 public int ComponentCount
701 int components = 0;
702 TraverseVertices(false, null, delegate(V v) { components++; }, null);
703 return components;
707 public ICollectionValue<KeyValuePair<V, IGraph<V, E, W>>> Components()
709 ArrayList<KeyValuePair<V, IGraph<V, E, W>>> retval = new ArrayList<KeyValuePair<V, IGraph<V, E, W>>>();
710 HashGraph<V, E, W> component;
711 ArrayList<V> vertices = null;
712 Action<Edge<V, E>> edgeaction = delegate(Edge<V, E> e)
714 vertices.Add(e.end);
716 Action<V> beforecomponent = delegate(V v)
718 vertices = new ArrayList<V>();
719 vertices.Add(v);
721 Action<V> aftercomponent = delegate(V v)
723 //component = SubGraph(vertices);
724 component = new HashGraph<V, E, W>(weight);
725 foreach (V start in vertices)
727 //component.graph[start] = graph[start].Clone();
728 HashDictionary<V, E> edgeset = component.graph[start] = new HashDictionary<V, E>();
729 foreach (KeyValuePair<V, E> adjacent in graph[start])
730 edgeset[adjacent.Key] = adjacent.Value;
732 retval.Add(new KeyValuePair<V, IGraph<V, E, W>>(v, component));
734 TraverseVertices(false, edgeaction, beforecomponent, aftercomponent);
735 return retval;
738 [UsedBy("test1")]
739 public void TraverseVertices(bool bfs, V start, Action<Edge<V, E>> act)
741 if (!graph.Contains(start))
742 throw new ArgumentException("start Vertex not in graph");
743 IList<Edge<V, E>> todo = new LinkedList<Edge<V, E>>();
744 todo.FIFO = bfs;
745 HashSet<V> seen = new HashSet<V>();
746 V v;
747 while (!todo.IsEmpty || seen.Count == 0)
749 if (seen.Count > 1)
751 Edge<V, E> e = todo.Remove();
752 if (act != null)
753 act(e);
754 v = e.end;
756 else
758 seen.Add(start);
759 v = start;
762 HashDictionary<V, E> adjacent;
763 if (graph.Find(v, out adjacent))
765 foreach (KeyValuePair<V, E> p in adjacent)
767 V end = p.Key;
768 if (!seen.FindOrAdd(ref end))
769 todo.Add(new Edge<V, E>(v, end, p.Value));
775 public void TraverseVertices(bool bfs, Action<V> act)
777 TraverseVertices(bfs, delegate(Edge<V, E> e) { act(e.end); }, act, null);
780 //TODO: merge the hash set here with the intra omponent one?
781 public void TraverseVertices(bool bfs, Action<Edge<V, E>> act, Action<V> beforecomponent, Action<V> aftercomponent)
783 HashSet<V> missing = new HashSet<V>();
784 missing.AddAll(Vertices());
785 Action<Edge<V, E>> myact = act + delegate(Edge<V, E> e) { missing.Remove(e.end); };
786 Action<V> mybeforecomponent = beforecomponent + delegate(V v) { missing.Remove(v); };
787 while (!missing.IsEmpty)
789 V start = default(V);
790 foreach (V v in missing)
791 { start = v; break; }
792 mybeforecomponent(start);
793 TraverseVertices(bfs, start, myact);
794 if (aftercomponent != null)
795 aftercomponent(start);
799 delegate void Visitor(V v, V parent, bool atRoot);
801 //TODO: allow actions to be null
802 [UsedBy("testDFS")]
803 public void DepthFirstSearch(V start, Action<V> before, Action<V> after,
804 Action<Edge<V, E>> onfollow, Action<Edge<V, E>> onfollowed, Action<Edge<V, E>> onnotfollowed)
806 HashSet<V> seen = new HashSet<V>();
807 seen.Add(start);
808 //If we do not first set visit = null, the compiler will complain at visit(end)
809 //that visit is uninitialized
810 Visitor visit = null;
811 visit = delegate(V v, V parent, bool atRoot)
813 before(v);
814 HashDictionary<V, E> adjacent;
815 if (graph.Find(v, out adjacent))
816 foreach (KeyValuePair<V, E> p in adjacent)
818 V end = p.Key;
819 Edge<V, E> e = new Edge<V, E>(v, end, p.Value);
820 if (!seen.FindOrAdd(ref end))
822 onfollow(e);
823 visit(end, v, false);
824 onfollowed(e);
826 else
828 if (!atRoot && !parent.Equals(end))
829 onnotfollowed(e);
832 after(v);
834 visit(start, default(V), true);
837 public void PriorityFirstTraverse(bool accumulated, V start, EdgeAction<V, E, W> act)
839 if (!graph.Contains(start))
840 throw new ArgumentException("Graph does not contain start");
841 IPriorityQueue<W> fringe = new IntervalHeap<W>();
842 HashDictionary<V, IPriorityQueueHandle<W>> seen = new HashDictionary<V, IPriorityQueueHandle<W>>();
843 HashDictionary<IPriorityQueueHandle<W>, Edge<V, E>> bestedge = new HashDictionary<IPriorityQueueHandle<W>, Edge<V, E>>();
845 IPriorityQueueHandle<W> h = null;
846 V current;
847 W currentdist;
848 while (!fringe.IsEmpty || seen.Count == 0)
850 if (seen.Count == 0)
852 seen.Add(start, h);
853 current = start;
854 currentdist = default(W);
856 else
858 currentdist = fringe.DeleteMin(out h);
859 Edge<V, E> e = bestedge[h];
860 if (!act(e, currentdist))
861 break;
862 bestedge.Remove(h);
863 current = e.end;
865 HashDictionary<V, E> adjacentnodes;
866 if (graph.Find(current, out adjacentnodes))
867 foreach (KeyValuePair<V, E> adjacent in adjacentnodes)
869 V end = adjacent.Key;
870 E edgedata = adjacent.Value;
871 W dist = weight.Weight(edgedata), olddist;
872 if (accumulated && !current.Equals(start)) dist = weight.Add(currentdist, weight.Weight(edgedata));
873 if (!seen.Find(end, out h))
875 h = null;
876 fringe.Add(ref h, dist);
877 seen[end] = h;
878 bestedge[h] = new Edge<V, E>(current, end, edgedata);
880 else if (fringe.Find(h, out olddist) && dist.CompareTo(olddist) < 0)
882 fringe[h] = dist;
883 bestedge[h] = new Edge<V, E>(current, end, edgedata);
889 public W Distance(V start, V end)
891 W dist = default(W);
892 bool found = false;
893 PriorityFirstTraverse(true, start, delegate(Edge<V, E> e, W w)
895 if (end.Equals(e.end)) { dist = w; found = true; return false; }
896 else return true;
898 if (found)
899 return dist;
900 throw new ArgumentException(String.Format("No path from {0} to {1}", start, end));
904 public ICollectionValue<Edge<V, E>> ShortestPath(V start, V end)
906 HashDictionary<V, Edge<V, E>> backtrack = new HashDictionary<V, Edge<V, E>>();
907 PriorityFirstTraverse(true, start, delegate(Edge<V, E> e, W w) { backtrack[e.end] = e; return !end.Equals(e.end); });
908 ArrayList<Edge<V, E>> path = new ArrayList<Edge<V, E>>();
909 Edge<V, E> edge;
910 V v = end;
911 while (backtrack.Find(v, out edge))
913 path.Add(edge);
914 v = edge.start;
916 if (path.IsEmpty)
917 throw new ArgumentException(String.Format("No path from {0} to {1}", start, end));
918 path.Reverse();
919 return path;
922 /// <summary>
923 /// NB: assume connected, throw exception if not
924 /// </summary>
925 /// <typeparam name="W"></typeparam>
926 /// <param name="edgeWeight"></param>
927 /// <returns></returns>
928 public IGraph<V, E, W> MinimumSpanningTree(out V start)
930 ArrayList<Edge<V, E>> edges = new ArrayList<Edge<V, E>>();
931 start = default(V);
932 foreach (V v in graph.Keys)
933 { start = v; break; }
934 PriorityFirstTraverse(false, start, delegate(Edge<V, E> e, W w) { edges.Add(e); return true; });
935 if (edges.Count != graph.Count - 1)
936 throw new ArgumentException("Graph not connected");
937 return new HashGraph<V, E, W>(weight, edges);
940 public ICollectionValue<Edge<V, E>> ApproximateMWPM()
942 //Assume graph complete and even number of vertices
943 HashGraph<V, E, W> clone = new HashGraph<V, E, W>(weight, Edges());
944 ArrayList<Edge<V, E>> evenpath = new ArrayList<Edge<V, E>>();
945 ArrayList<Edge<V, E>> oddpath = new ArrayList<Edge<V, E>>();
946 V start = default(V);
947 foreach (V v in clone.Vertices()) { start = v; break; }
948 V current = start;
949 W evenweight, oddweight;
950 evenweight = oddweight = default(W);
951 bool even = true;
952 while (clone.VertexCount > 0)
954 V bestvertex = default(V);
955 E bestedge = default(E);
956 W bestweight = default(W);
957 if (clone.VertexCount == 1)
959 bestvertex = start;
960 bestedge = graph[current][start];
961 bestweight = weight.Weight(bestedge);
963 else
965 bool first = true;
966 foreach (KeyValuePair<V, E> p in clone.graph[current])
968 W thisweight = weight.Weight(p.Value);
969 if (first || bestweight.CompareTo(thisweight) > 0)
971 bestvertex = p.Key;
972 bestweight = thisweight;
973 bestedge = p.Value;
975 first = false;
978 clone.RemoveVertex(current);
979 //Console.WriteLine("-* {0} / {1} / {2}", bestvertex, bestweight, tour.Count);
980 if (even)
982 evenweight = evenpath.Count < 1 ? bestweight : weight.Add(evenweight, bestweight);
983 evenpath.Add(new Edge<V, E>(current, bestvertex, bestedge));
985 else
987 oddweight = oddpath.Count < 1 ? bestweight : weight.Add(oddweight, bestweight);
988 oddpath.Add(new Edge<V, E>(current, bestvertex, bestedge));
990 current = bestvertex;
991 even = !even;
993 //Console.WriteLine("Totalweights: even: {0} and odd: {1}", evenweight, oddweight);
994 return evenweight.CompareTo(oddweight) < 0 ? evenpath : oddpath;
997 /// <summary>
998 /// The construction is performed as follows:
999 /// Start at some vertex. Greedily construct a path starting there by
1000 /// following edges at random until no more unused edges are available
1001 /// from the current node, which must be the start node. Then follow
1002 /// the path constructed so far and whenever we meet a vertex with
1003 /// unused edges, construct a path from there greedily as above,
1004 /// inserting into the path in front of us.
1005 ///
1006 /// The algorithm will use constant time for each vertex added
1007 /// to the path and
1008 ///
1009 /// Illustrates use of views as a safe version of listnode pointers
1010 /// and hashed linked lists for choosing some item in constant time combined
1011 /// with (expected) constant time remove.
1012 /// </summary>
1013 /// <returns></returns>
1014 public IList<V> EulerTour()
1016 bool debug = false;
1017 //Assert connected and all degrees even. (Connected is checked at the end)
1018 string fmt = "Graph does not have a closed Euler tour: vertex {0} has odd degree {1}";
1019 foreach (KeyValuePair<V, HashDictionary<V, E>> adj in graph)
1020 if (adj.Value.Count % 2 != 0)
1021 throw new ArgumentException(String.Format(fmt, adj.Key, adj.Value.Count));
1023 LinkedList<V> path = new LinkedList<V>();
1024 //Clone the graph data to keep track of used edges.
1025 HashDictionary<V, HashedArrayList<V>> edges = new HashDictionary<V, HashedArrayList<V>>();
1026 V start = default(V);
1027 HashedArrayList<V> adjacent = null;
1028 foreach (KeyValuePair<V, HashDictionary<V, E>> p in graph)
1030 adjacent = new HashedArrayList<V>();
1031 adjacent.AddAll(p.Value.Keys);
1032 start = p.Key;
1033 edges.Add(start, adjacent);
1036 path.Add(start);
1037 IList<V> view = path.View(0, 1);
1038 while (adjacent.Count > 0)
1040 V current = view[0];
1041 if (debug) Console.WriteLine("==> {0}", current);
1042 //Augment the path (randomly) until we return here and all edges
1043 while (adjacent.Count > 0)
1045 if (debug) Console.WriteLine(" => {0}, {1}", current, path.Count);
1046 V next = adjacent.RemoveFirst();
1047 view.Add(next);
1048 if (debug) Console.WriteLine("EDGE: " + current + "->" + next);
1049 if (!edges[next].Remove(current))
1050 Console.WriteLine("Bad");
1051 current = next;
1052 adjacent = edges[current];
1054 //When we get here, the view contains a closed path, i.e.
1055 //view[view.Count-1] == view[0] and we have followed all edges from view[0]
1056 //We slide forward along the rest of the path constructed so far and stop at the
1057 //first vertex with still unfollwed edges.
1058 while (view.Offset < path.Count - 1 && adjacent.Count == 0)
1060 view.Slide(1, 1);
1061 if (debug) Console.WriteLine(" -> {0}, {1}", view[0], path.Count);
1062 adjacent = edges[view[0]];
1065 if (path.Count <= edges.Count)
1066 throw new ArgumentException("Graph was not connected");
1067 return path;
1070 /// <summary>
1071 /// The purpose of this struct is to be able to create and add new,
1072 /// synthetic vertices to a graph.
1073 /// </summary>
1074 struct Vplus : IEquatable<Vplus>
1076 internal readonly V vertex; internal readonly int id;
1077 static SCG.IEqualityComparer<V> vequalityComparer = EqualityComparer<V>.Default;
1078 internal Vplus(V v) { vertex = v; id = 0; }
1079 internal Vplus(int i) { vertex = default(V); id = i; }
1080 //We should override Equals and GetHashCode
1082 public override string ToString()
1083 { return id == 0 ? String.Format("real({0})", vertex) : String.Format("fake({0})", id); }
1085 public override bool Equals(object obj) { throw new NotImplementedException(); }
1087 public bool Equals(Vplus other) { return vequalityComparer.Equals(vertex, other.vertex) && id == other.id; }
1089 public override int GetHashCode() { return vequalityComparer.GetHashCode(vertex) + id; }
1092 /// <summary>
1093 ///
1094 /// </summary>
1095 /// <returns></returns>
1096 public IDirectedCollectionValue<V> ApproximateTSP2()
1098 /* Construct a minimum spanning tree for the graph */
1099 V root;
1100 IGraph<V, E, W> tree = MinimumSpanningTree(out root);
1102 //Console.WriteLine("========= Matching of odd vertices of mst =========");
1103 ArrayList<V> oddvertices = new ArrayList<V>();
1104 foreach (V v in tree.Vertices())
1105 if (tree.Adjacent(v).Count % 2 != 0)
1106 oddvertices.Add(v);
1108 ICollectionValue<Edge<V, E>> matching = SubGraph(oddvertices).ApproximateMWPM();
1110 //Console.WriteLine("========= Fuse matching and tree =========");
1111 //We must split the edges of the matching with fake temporary vertices
1112 //since the matching and the tree may have common edges
1114 HashGraph<Vplus, E, W> fused = new HashGraph<Vplus, E, W>(weight);
1115 foreach (Edge<V, E> e in tree.Edges())
1116 fused.AddEdge(new Vplus(e.start), new Vplus(e.end), e.edgedata);
1117 int fakeid = 1;
1118 foreach (Edge<V, E> e in matching)
1120 Vplus fakevertex = new Vplus(fakeid++);
1121 fused.AddEdge(new Vplus(e.start), fakevertex, e.edgedata);
1122 fused.AddEdge(fakevertex, new Vplus(e.end), e.edgedata);
1124 fused.Print(Console.Out);
1126 //Console.WriteLine("========= Remove fake vertices and perform shortcuts =========");
1127 IList<Vplus> fusedtour = fused.EulerTour();
1128 HashSet<V> seen = new HashSet<V>();
1129 IList<V> tour = new ArrayList<V>();
1131 foreach (Vplus vplus in fused.EulerTour())
1133 V v = vplus.vertex;
1134 if (vplus.id == 0 && !seen.FindOrAdd(ref v))
1135 tour.Add(v);
1137 return tour;
1140 /// <summary>
1141 /// (Refer to the litterature, Vazirani)
1142 ///
1143 /// (Describe: MST+Euler+shortcuts)
1144 /// </summary>
1145 /// <returns></returns>
1146 [UsedBy("testTSP")]
1147 public IDirectedCollectionValue<V> ApproximateTSP()
1149 /* Construct a minimum spanning tree for the graph */
1150 V root;
1151 IGraph<V, E, W> tree = MinimumSpanningTree(out root);
1153 /* (Virtually) double all edges of MST and construct an Euler tour of the vertices*/
1154 LinkedList<V> tour = new LinkedList<V>();
1155 tour.Add(root);
1156 tour.Add(root);
1157 IList<V> view = tour.View(1, 1);
1159 Action<Edge<V, E>> onfollow = delegate(Edge<V, E> e)
1161 //slide the view until it points to the last copy of e.start
1162 while (!view[0].Equals(e.start))
1163 view.Slide(1);
1164 //then insert two copies of e.end and slide the view one backwards
1165 view.InsertFirst(e.end);
1166 view.InsertFirst(e.end);
1167 view.Slide(1, 1);
1170 tree.TraverseVertices(false, root, onfollow);
1172 /* Finally, slide along the Euler tour and shortcut by removing vertices already seen*/
1173 HashSet<V> seen = new HashSet<V>();
1174 view = tour.View(0, tour.Count);
1175 while (view.Offset < tour.Count - 1)
1177 V v = view[0];
1178 if (seen.FindOrAdd(ref v))
1179 view.RemoveFirst();
1180 else
1181 view.Slide(1, view.Count - 1);
1183 return tour;
1186 public void Print(System.IO.TextWriter output)
1188 output.WriteLine("Graph has {0} vertices, {1} edges, {2} components", graph.Count, edgecount, ComponentCount);
1189 foreach (KeyValuePair<V, HashDictionary<V, E>> p in graph)
1191 output.Write(" {0} -> ", p.Key);
1192 foreach (KeyValuePair<V, E> p2 in p.Value)
1193 output.Write("{1} (data {2}), ", p.Key, p2.Key, p2.Value);
1194 output.WriteLine();
1199 /// <summary>
1200 /// A weight on a graph that assigns the weight 1 to every edge.
1201 /// </summary>
1202 /// <typeparam name="E">(Ignored) type of edgedata</typeparam>
1203 class CountWeight<E> : IWeight<E, int>
1205 public int Weight(E edgedata) { return 1; }
1207 public int Add(int w1, int w2) { return w1 + w2; }
1210 /// <summary>
1211 /// A weight on an IGraph&lt;V,int&gt; that uses the value of the edgedata as the weight value.
1212 /// </summary>
1213 class IntWeight : IWeight<int, int>
1216 public int Weight(int edgedata) { return edgedata; }
1218 public int Add(int w1, int w2) { return w1 + w2; }
1222 /// <summary>
1223 /// A weight on an IGraph&lt;V,double&gt; that uses the value of the edgedata as the weight value.
1224 /// </summary>
1225 class DoubleWeight : IWeight<double, double>
1228 public double Weight(double edgedata) { return edgedata; }
1230 public double Add(double w1, double w2) { return w1 + w2; }
1234 /// <summary>
1235 /// Attribute used for marking which examples use a particuler graph method
1236 /// </summary>
1237 class UsedByAttribute : Attribute
1239 string[] tests;
1240 internal UsedByAttribute(params string[] tests) { this.tests = tests; }
1242 public override string ToString()
1244 System.Text.StringBuilder sb = new System.Text.StringBuilder();
1245 for (int i = 0; i < tests.Length; i++)
1247 if (i > 0)
1248 sb.Append(", ");
1249 sb.Append(tests[i]);
1251 return sb.ToString();
1255 /// <summary>
1256 /// Attribute for marking example methods with a description
1257 /// </summary>
1258 class ExampleDescriptionAttribute : Attribute
1260 string text;
1261 internal ExampleDescriptionAttribute(string text) { this.text = text; }
1263 public override string ToString() { return text; }
1266 /// <summary>
1267 /// A selection of test cases
1268 /// </summary>
1269 class Test
1271 static SCG.IEnumerable<Edge<int, int>> Grid(int n)
1273 Random ran = new Random(1717);
1274 for (int i = 1; i <= n; i++)
1276 for (int j = 1; j <= n; j++)
1278 yield return new Edge<int, int>(1000 * i + j, 1000 * (i + 1) + j, ran.Next(1, 100));
1279 yield return new Edge<int, int>(1000 * i + j, 1000 * i + j + 1, ran.Next(1, 100));
1284 static SCG.IEnumerable<Edge<string, int>> Snake(int n)
1286 for (int i = 1; i <= n; i++)
1288 yield return new Edge<string, int>("U" + i, "L" + i, 1);
1289 yield return new Edge<string, int>("U" + i, "U" + (i + 1), i % 2 == 0 ? 1 : 10);
1290 yield return new Edge<string, int>("L" + i, "L" + (i + 1), i % 2 == 0 ? 10 : 1);
1294 /// <summary>
1295 /// Create the edges of a forest of complete binary trees.
1296 /// </summary>
1297 /// <param name="treeCount">Number of trees</param>
1298 /// <param name="height">Height of trees</param>
1299 /// <returns></returns>
1300 static SCG.IEnumerable<Edge<string, int>> Forest(int treeCount, int height)
1302 for (int i = 0; i < treeCount; i++)
1304 IList<string> q = new ArrayList<string>();
1305 string root = String.Format("[{0}]", i);
1306 int lmax = height + root.Length;
1307 q.Add(root);
1308 while (!q.IsEmpty)
1310 string s = q.Remove();
1311 string s2 = s + "L";
1312 if (s2.Length < lmax)
1313 q.Add(s2);
1314 yield return new Edge<string, int>(s, s2, 0);
1315 s2 = s + "R";
1316 if (s2.Length < lmax)
1317 q.Add(s2);
1318 yield return new Edge<string, int>(s, s2, 0);
1323 /// <summary>
1324 /// Create edges of a graph correspondingto a "wheel" shape: the ecnter and equidistant
1325 /// points around the perimeter. The edgedata and edge weights are the euclidean distances.
1326 /// </summary>
1327 /// <param name="complete">True means the graph will be complete, false that the graph
1328 /// will have edges for the spokes and between neighboring perimeter vetices.</param>
1329 /// <param name="n">The number of perimeter vertices, must be at least 3.</param>
1330 /// <returns>An enumerable with the edges</returns>
1331 static SCG.IEnumerable<Edge<string, double>> Wheel(bool complete, int n)
1333 if (n < 3)
1334 throw new ArgumentOutOfRangeException("n must be at least 3");
1335 string center = "C";
1336 string[] perimeter = new string[n];
1337 for (int i = 0; i < n; i++)
1339 perimeter[i] = "P" + i;
1340 yield return new Edge<string, double>(perimeter[i], center, 1);
1342 if (complete)
1343 for (int i = 0; i < n - 1; i++)
1344 for (int j = i + 1; j < n; j++)
1345 yield return new Edge<string, double>(perimeter[i], perimeter[j], 2 * Math.Sin((j - i) * Math.PI / n));
1346 else
1348 for (int i = 0; i < n - 1; i++)
1349 yield return new Edge<string, double>(perimeter[i], perimeter[i + 1], 2 * Math.Sin(Math.PI / n));
1350 yield return new Edge<string, double>(perimeter[n - 1], perimeter[0], 2 * Math.Sin(Math.PI / n));
1355 /// <summary>
1356 /// []
1357 /// </summary>
1358 [ExampleDescription("Basic BFS and DFS using TraverseVertices method")]
1359 static void test1()
1361 IGraph<int, int, int> g = new HashGraph<int, int, int>(new CountWeight<int>(), Grid(3));
1362 Console.WriteLine("Edge count: {0}", g.Edges().Count);
1363 Console.WriteLine("BFS:");
1364 g.TraverseVertices(true, 1001, delegate(Edge<int, int> e) { Console.WriteLine(e); });
1365 Console.WriteLine("DFS:");
1366 g.TraverseVertices(false, 1001, delegate(Edge<int, int> e) { Console.WriteLine(e); });
1369 /// <summary>
1370 ///
1371 /// </summary>
1372 [ExampleDescription("Component methods")]
1373 static void testCOMP()
1375 IGraph<string, int, int> g = new HashGraph<string, int, int>(new CountWeight<int>(), Forest(2, 2));
1376 Console.WriteLine("Forest has: Vertices: {0}, Edges: {1}, Components: {2}", g.VertexCount, g.EdgeCount, g.ComponentCount);
1377 //g.Print(Console.Out);
1378 foreach (KeyValuePair<string, IGraph<string, int, int>> comp in g.Components())
1380 Console.WriteLine("Component of {0}:", comp.Key);
1381 comp.Value.Print(Console.Out);
1385 //TODO: remove?
1386 static void test3()
1388 HashGraph<int, int, int> g = new HashGraph<int, int, int>(new CountWeight<int>(), Grid(5));
1389 g.Print(Console.Out);
1390 //EdgeWeight<int, IntWeight> weight = delegate(int i) { return i; };
1391 Console.WriteLine("========= PFS accum =========");
1392 g.PriorityFirstTraverse(
1393 true,
1394 2002,
1395 delegate(Edge<int, int> e, int d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
1396 Console.WriteLine("========= PFS not accum =========");
1397 g.PriorityFirstTraverse(
1398 false,
1399 2002,
1400 delegate(Edge<int, int> e, int d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
1401 Console.WriteLine("========= MST =========");
1402 int root;
1403 g.MinimumSpanningTree(out root).Print(Console.Out);
1404 Console.WriteLine("========= SP =========");
1405 foreach (Edge<int, int> edge in g.ShortestPath(1001, 5005))
1406 Console.WriteLine(edge);
1409 static void test4()
1411 IGraph<string, int, int> g = new HashGraph<string, int, int>(new IntWeight(), Snake(5));
1412 Console.WriteLine("Edge count: {0}", g.Edges().Count);
1413 Console.WriteLine("========= PFS =========");
1414 g.PriorityFirstTraverse(false,
1415 "U3",
1416 delegate(Edge<string, int> e, int d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
1417 Console.WriteLine("========= MST =========");
1418 string root;
1419 IGraph<string, int, int> mst = g.MinimumSpanningTree(out root);
1420 mst.Print(Console.Out);
1421 Console.WriteLine("DFS:");
1422 mst.TraverseVertices(false, root, delegate(Edge<string, int> e) { Console.WriteLine(e); });
1423 Console.WriteLine("ATSP:");
1424 int first = 0;
1425 foreach (string s in g.ApproximateTSP())
1427 Console.Write((first++ == 0 ? "" : " -> ") + s);
1431 /// <summary>
1432 /// This example examines the two variants of a priority-first search:
1433 /// with accumulated weights, leading to shortest paths from start;
1434 /// with non-acumulated weights, leading to a minimum spanning tree.
1435 /// </summary>
1436 [ExampleDescription("Priority-first-search with and without accumulated weights")]
1437 static void testPFS()
1439 IGraph<string, double, double> g = new HashGraph<string, double, double>(new DoubleWeight(), Wheel(false, 10));
1440 g.Print(Console.Out);
1441 Console.WriteLine("========= PFS non-accumulated weights (-> MST) =========");
1442 g.PriorityFirstTraverse(false,
1443 "P0",
1444 delegate(Edge<string, double> e, double d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
1445 Console.WriteLine("========= PFS accumulated weights (-> Shortst paths from start) =========");
1446 g.PriorityFirstTraverse(true,
1447 "P0",
1448 delegate(Edge<string, double> e, double d) { Console.WriteLine("Edge: {0}, at distance {1}", e, d); return true; });
1451 /// <summary>
1452 ///
1453 ///
1454 /// (Refer to Vazirani, or do that where ApproximateTSP is implemented)
1455 ///
1456 /// Note that the tour created is not optimal. [Describe why]
1457 /// </summary>
1458 [ExampleDescription("Approximate TSP")]
1459 static void testTSP()
1461 IGraph<string, double, double> g = new HashGraph<string, double, double>(new DoubleWeight(), Wheel(true, 10));
1462 //g.Print(Console.Out);
1463 Console.WriteLine("========= MST =========");
1464 string root;
1465 IGraph<string, double, double> mst = g.MinimumSpanningTree(out root);
1466 mst.TraverseVertices(false,
1467 root,
1468 delegate(Edge<string, double> e) { Console.WriteLine("Edge: {0} -> {1}", e.start, e.end); });
1469 Console.WriteLine("========= Approximate TSP =========");
1470 int first = 0;
1471 foreach (string s in g.ApproximateTSP())
1473 Console.Write((first++ == 0 ? "" : " -> ") + s);
1477 /// <summary>
1478 ///
1479 ///
1480 /// (Refer to Vazirani, or do that where ApproximateTSP is implemented)
1481 ///
1482 /// Note that the tour created is not optimal. [Describe why]
1483 /// </summary>
1484 [ExampleDescription("Approximate TSP2")]
1485 static void testTSP2()
1487 HashGraph<string, double, double> g = new HashGraph<string, double, double>(new DoubleWeight(), Wheel(true, 20));
1489 foreach (string s in g.ApproximateTSP2())
1490 Console.WriteLine("# " + s);
1491 //g.Print(Console.Out);
1493 Console.WriteLine("========= MST =========");
1494 string root;
1495 IGraph<string, double, double> mst = g.MinimumSpanningTree(out root);
1496 mst.TraverseVertices(false,
1497 root,
1498 delegate(Edge<string, double> e) { Console.WriteLine("Edge: {0} -> {1}", e.start, e.end); });
1499 ArrayList<string> oddvertices = new ArrayList<string>();
1500 foreach (string v in mst.Vertices())
1501 if (mst.Adjacent(v).Count % 2 != 0)
1502 oddvertices.Add(v);
1504 Console.WriteLine("========= Matching of odd vertices of mst =========");
1505 ICollectionValue<Edge<string, double>> matching = g.SubGraph(oddvertices).ApproximateMWPM();
1507 Console.WriteLine("========= Add matching to mst =========");
1508 //We must split the edges of the matchin with fake temporary vertices
1509 //(For a general vertex type, we would have to augment it to Pair<V,int>
1510 int fake = 0;
1511 foreach (Edge<string, double> e in matching)
1513 string fakevertex = "_" + (fake++);
1514 mst.AddEdge(e.start, fakevertex, 0);
1515 mst.AddEdge(fakevertex, e.end, e.edgedata);
1517 //mst.Print(Console.Out);
1519 IList<string> tour = mst.EulerTour(), view = tour.View(1, tour.Count - 1);
1521 //Remove fake vertices
1522 while (view.Count > 0)
1523 if (view[0].StartsWith("_"))
1524 view.RemoveFirst();
1525 else
1526 view.Slide(1, view.Count - 1);
1528 Console.WriteLine("========= Approximate TSP 2 =========");
1529 //Short cut
1530 view = tour.View(1, tour.Count - 1);
1531 HashSet<string> seen = new HashSet<string>();
1533 while (view.Count > 0)
1535 string s = view[0];
1536 if (seen.FindOrAdd(ref s))
1537 view.RemoveFirst();
1538 else
1539 view.Slide(1, view.Count - 1);
1542 foreach (string s in tour)
1543 Console.WriteLine(". " + s);*/
1546 /// <summary>
1547 ///
1548 /// </summary>
1549 static void testEuler()
1551 HashGraph<string, double, double> g = new HashGraph<string, double, double>(new DoubleWeight(), Wheel(true, 6));
1552 foreach (string s in g.EulerTour())
1553 Console.Write(s + " ");
1554 Console.WriteLine();
1557 /// <summary>
1558 /// An articulation point in a graph is a vertex, whose removal will
1559 /// disconnect the graph (or its component). This example uses the
1560 /// extended DepthFirstSearch method to compute articulation points
1561 /// of a graph.
1562 ///
1563 /// (Refer to Sedgewick. )
1564 ///
1565 /// Each vertex is given an index in traversal order.
1566 /// For each vertex, we compute the least index reachable by going downwards
1567 /// in the DFS tree and then following a single non-dfs edge.
1568 ///
1569 /// Since we cannot store the DFS indices in the vertices without changing the
1570 /// (assumed given) vertex type, V, we remember the indices in a V-&gt;int
1571 /// hash dictionary, index. The "least reachable" values are then stored in an
1572 /// array keyed by the index.
1573 ///
1574 /// The root of the search is an articulation point if it has more than one
1575 /// outgoing DFS edges. Other articulation points are non-root vertices, va,
1576 /// with an outgoing DFS edge, where the the least reachable index of the other
1577 /// vertex is greater or equal to the index of va.
1578 /// </summary>
1579 [ExampleDescription("Using the advanced DFS to compute articulation points")]
1580 static void testDFS()
1582 HashGraph<string, int, int> g = new HashGraph<string, int, int>(new IntWeight());
1583 g.AddEdge("A", "B", 0);
1584 g.AddEdge("A", "E", 0);
1585 g.AddEdge("B", "E", 0);
1586 g.AddEdge("B", "C", 0);
1587 g.AddEdge("B", "H", 0);
1588 g.AddEdge("H", "I", 0);
1589 g.AddEdge("B", "D", 0);
1590 g.AddEdge("C", "D", 0);
1591 g.AddEdge("C", "F", 0);
1592 g.AddEdge("C", "G", 0);
1593 g.AddEdge("F", "G", 0);
1595 HashDictionary<string, int> index = new HashDictionary<string, int>();
1596 int[] leastIndexReachableFrom = new int[g.VertexCount];
1597 int nextindex = 0;
1598 int outgoingFromRoot = 0;
1599 Action<string> beforevertex = delegate(string v)
1601 int i = (index[v] = nextindex++);
1602 leastIndexReachableFrom[i] = i;
1604 Action<string> aftervertex = delegate(string v)
1606 int i = index[v];
1607 if (i == 0 && outgoingFromRoot > 1)
1608 Console.WriteLine("Articulation point: {0} ({1}>1 outgoing DFS edges from start)",
1609 v, outgoingFromRoot);
1611 Action<Edge<string, int>> onfollow = delegate(Edge<string, int> e)
1614 Action<Edge<string, int>> onfollowed = delegate(Edge<string, int> e)
1616 int startind = index[e.start], endind = index[e.end];
1617 if (startind == 0)
1618 outgoingFromRoot++;
1619 else
1621 int leastIndexReachable = leastIndexReachableFrom[endind];
1622 if (leastIndexReachable >= startind)
1623 Console.WriteLine("Articulation point: {0} (least index reachable via {3} is {1} >= this index {2})",
1624 e.start, leastIndexReachable, startind, e);
1625 if (leastIndexReachableFrom[startind] > leastIndexReachable)
1626 leastIndexReachableFrom[startind] = leastIndexReachable;
1629 Action<Edge<string, int>> onnotfollowed = delegate(Edge<string, int> e)
1631 int startind = index[e.start], endind = index[e.end];
1632 if (leastIndexReachableFrom[startind] > endind)
1633 leastIndexReachableFrom[startind] = endind;
1636 string root = "C";
1637 g.DepthFirstSearch(root, beforevertex, aftervertex, onfollow, onfollowed, onnotfollowed);
1638 Console.WriteLine("Edges:");
1639 foreach (Edge<string, int> e in g.Edges())
1640 Console.WriteLine("/ {0}", e);
1643 static void Main(String[] args)
1645 if (args.Length != 1)
1647 Console.WriteLine("Usage: Graph.exe testno");
1648 System.Reflection.MethodInfo[] mis = typeof(Test).GetMethods(
1649 System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
1650 foreach (System.Reflection.MethodInfo mi in mis)
1652 if (mi.GetParameters().Length == 0 && mi.ReturnType == typeof(void) && mi.Name.StartsWith("test"))
1654 object[] attrs = mi.GetCustomAttributes(typeof(ExampleDescriptionAttribute), false);
1655 Console.WriteLine(" {0} : {1}", mi.Name.Substring(4), attrs.Length > 0 ? attrs[0] : "");
1659 else
1661 string testMethodName = String.Format("test{0}", args[0]);
1663 System.Reflection.MethodInfo mi = typeof(Test).GetMethod(testMethodName,
1664 System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
1666 if (mi == null)
1667 Console.WriteLine("No such testmethod, {0}", testMethodName);
1668 else
1670 object[] attrs = mi.GetCustomAttributes(typeof(ExampleDescriptionAttribute), false);
1671 Console.WriteLine("============================== {0}() ==================================", testMethodName);
1672 Console.WriteLine("Description: {0}", attrs.Length > 0 ? attrs[0] : "None");
1673 Console.WriteLine("===========================================================================");
1674 mi.Invoke(null, null);