public void Run() { // create random bipartite graph with V vertices and E edges; then add F random edges const int vv = 20; const int e = 30; const int f = 5; var graph = new Graph(vv); var vertices = new int[vv]; for (var i = 0; i < vv; i++) vertices[i] = i; StdRandom.Shuffle(vertices); for (var i = 0; i < e; i++) { var v = StdRandom.Uniform(vv / 2); var w = StdRandom.Uniform(vv / 2); graph.AddEdge(vertices[v], vertices[vv / 2 + w]); } // add F extra edges for (var i = 0; i < f; i++) { var v = StdRandom.Uniform(vv); var w = StdRandom.Uniform(vv); graph.AddEdge(v, w); } Console.WriteLine(graph); var b = new Bipartite(graph); if (b.IsBipartite()) { Console.WriteLine("Graph is bipartite"); for (var v = 0; v < graph.V; v++) { Console.WriteLine(v + ": " + b.Color(v)); } } else { Console.Write("Graph has an odd-length cycle: "); foreach (int x in b.OddCycle()) { Console.Write(x + " "); } Console.WriteLine(); } Console.ReadLine(); }
public void Run() { const int vv = 20; const int e = 30; // Eulerian cycle var g1 = GraphGenerator.EulerianCycle(vv, e); EulerianCycle.UnitTest(g1, "Eulerian cycle"); // Eulerian path var g2 = GraphGenerator.EulerianCycle(vv, e); EulerianCycle.UnitTest(g2, "Eulerian path"); // empty graph var g3 = new Graph(vv); EulerianCycle.UnitTest(g3, "empty graph"); // self loop var g4 = new Graph(vv); var v4 = StdRandom.Uniform(vv); g4.AddEdge(v4, v4); EulerianCycle.UnitTest(g4, "single self loop"); // union of two disjoint cycles var h1 = GraphGenerator.EulerianCycle(vv / 2, e / 2); var h2 = GraphGenerator.EulerianCycle(vv - vv / 2, e - e / 2); var perm = new int[vv]; for (var i = 0; i < vv; i++) perm[i] = i; StdRandom.Shuffle(perm); var g5 = new Graph(vv); for (var v = 0; v < h1.V; v++) foreach (int w in h1.Adj(v)) g5.AddEdge(perm[v], perm[w]); for (var v = 0; v < h2.V; v++) foreach (int w in h2.Adj(v)) g5.AddEdge(perm[vv / 2 + v], perm[vv / 2 + w]); EulerianCycle.UnitTest(g5, "Union of two disjoint cycles"); // random digraph var g6 = GraphGenerator.Simple(vv, e); EulerianCycle.UnitTest(g6, "simple graph"); Console.ReadLine(); }
/// <summary> /// Returns a complete binary tree graph on <tt>V</tt> vertices. /// </summary> /// <param name="v">V the number of vertices in the binary tree</param> /// <returns>a complete binary tree graph on <tt>V</tt> vertices</returns> public static Graph BinaryTree(int v) { var g = new Graph(v); var vertices = new int[v]; for (var i = 0; i < v; i++) vertices[i] = i; StdRandom.Shuffle(vertices); for (var i = 1; i < v; i++) { g.AddEdge(vertices[i], vertices[(i - 1) / 2]); } return g; }
private readonly ST<string, Integer> _st; // string -> index #endregion Fields #region Constructors /// <summary> /// Initializes a graph from a file using the specified delimiter. /// Each line in the file contains /// the name of a vertex, followed by a list of the names /// of the vertices adjacent to that vertex, separated by the delimiter. /// </summary> /// <param name="lines">array of string lines</param> /// <param name="delimiter">delimiter the delimiter between fields</param> public SymbolGraph(IList<string> lines, char delimiter) { _st = new ST<string, Integer>(); // First pass builds the index by reading strings to associate // distinct strings with an index // while (in.hasNextLine()) { foreach (var line in lines) { var a = line.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries); foreach (var word in a) { if (!_st.Contains(word)) _st.Put(word, _st.Size()); } } Console.WriteLine("Done reading"); // inverted index to get string keys in an aray _keys = new string[_st.Size()]; foreach (var name in _st.Keys()) { _keys[_st.Get(name)] = name; } // second pass builds the graph by connecting first vertex on each // line to all others G = new Graph(_st.Size()); foreach (var line in lines) { var a = line.Split(new[] { delimiter }, StringSplitOptions.RemoveEmptyEntries); int v = _st.Get(a[0]); for (var i = 1; i < a.Length; i++) { int w = _st.Get(a[i]); G.AddEdge(v, w); } } }
public void Run() { const int v = 20; const int e = 30; // Eulerian cycle var g1 = GraphGenerator.EulerianCycle(v, e); EulerianPath.UnitTest(g1, "Eulerian cycle"); // Eulerian path var g2 = GraphGenerator.EulerianPath(v, e); EulerianPath.UnitTest(g2, "Eulerian path"); // add one random edge var g3 = new Graph(g2); g3.AddEdge(StdRandom.Uniform(v), StdRandom.Uniform(v)); EulerianPath.UnitTest(g3, "one random edge added to Eulerian path"); // self loop var g4 = new Graph(v); var v4 = StdRandom.Uniform(v); g4.AddEdge(v4, v4); EulerianPath.UnitTest(g4, "single self loop"); // single edge var g5 = new Graph(v); g5.AddEdge(StdRandom.Uniform(v), StdRandom.Uniform(v)); EulerianPath.UnitTest(g5, "single edge"); // empty graph var g6 = new Graph(v); EulerianPath.UnitTest(g6, "empty graph"); // random graph var g7 = GraphGenerator.Simple(v, e); EulerianPath.UnitTest(g7, "simple graph"); Console.ReadLine(); }
/// <summary> /// Returns a random simple bipartite graph on <tt>V1</tt> and <tt>V2</tt> vertices /// with <tt>E</tt> edges. /// </summary> /// <param name="v1">V1 the number of vertices in one partition</param> /// <param name="v2">V2 the number of vertices in the other partition</param> /// <param name="e">E the number of edges</param> /// <returns>a random simple bipartite graph on <tt>V1</tt> and <tt>V2</tt> vertices, containing a total of <tt>E</tt> edges</returns> /// <exception cref="ArgumentException">if no such simple bipartite graph exists</exception> public static Graph Bipartite(int v1, int v2, int e) { if (e > (long)v1 * v2) throw new ArgumentException("Too many edges"); if (e < 0) throw new ArgumentException("Too few edges"); var g = new Graph(v1 + v2); var vertices = new int[v1 + v2]; for (var i = 0; i < v1 + v2; i++) vertices[i] = i; StdRandom.Shuffle(vertices); var set = new SET<EdgeU>(); while (g.E < e) { var i = StdRandom.Uniform(v1); var j = v1 + StdRandom.Uniform(v2); var edge = new EdgeU(vertices[i], vertices[j]); if (set.Contains(edge)) continue; set.Add(edge); g.AddEdge(vertices[i], vertices[j]); } return g; }
/// <summary> /// Returns a random simple bipartite graph on <tt>V1</tt> and <tt>V2</tt> vertices, /// containing each possible edge with probability <tt>p</tt>. /// </summary> /// <param name="v1">V1 the number of vertices in one partition</param> /// <param name="v2">V2 the number of vertices in the other partition</param> /// <param name="p">p the probability that the graph contains an edge with one endpoint in either side</param> /// <returns>a random simple bipartite graph on <tt>V1</tt> and <tt>V2</tt> vertices, containing each possible edge with probability <tt>p</tt></returns> /// <exception cref="ArgumentException">if probability is not between 0 and 1</exception> public static Graph Bipartite(int v1, int v2, double p) { if (p < 0.0 || p > 1.0) throw new ArgumentException("Probability must be between 0 and 1"); var vertices = new int[v1 + v2]; for (var i = 0; i < v1 + v2; i++) vertices[i] = i; StdRandom.Shuffle(vertices); var g = new Graph(v1 + v2); for (var i = 0; i < v1; i++) for (var j = 0; j < v2; j++) if (StdRandom.Bernoulli(p)) g.AddEdge(vertices[i], vertices[v1 + j]); return g; }
/// <summary> /// Returns a wheel graph on <tt>V</tt> vertices. /// </summary> /// <param name="v">V the number of vertices in the wheel</param> /// <returns>a wheel graph on <tt>V</tt> vertices: a single vertex connected to every vertex in a cycle on <tt>V-1</tt> vertices</returns> public static Graph Wheel(int v) { if (v <= 1) throw new ArgumentException("Number of vertices must be at least 2"); var g = new Graph(v); var vertices = new int[v]; for (var i = 0; i < v; i++) vertices[i] = i; StdRandom.Shuffle(vertices); // simple cycle on V-1 vertices for (var i = 1; i < v - 1; i++) { g.AddEdge(vertices[i], vertices[i + 1]); } g.AddEdge(vertices[v - 1], vertices[1]); // connect vertices[0] to every vertex on cycle for (var i = 1; i < v; i++) { g.AddEdge(vertices[0], vertices[i]); } return g; }
/// <summary> /// Returns a uniformly random tree on <tt>V</tt> vertices. /// This algorithm uses a Prufer sequence and takes time proportional to <em>V log V</em>. /// http://www.proofwiki.org/wiki/Labeled_Tree_from_Prüfer_Sequence /// http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.36.6484&rep=rep1&type=pdf /// </summary> /// <param name="v">V the number of vertices in the tree</param> /// <returns>a uniformly random tree on <tt>V</tt> vertices</returns> public static Graph Tree(int v) { var g = new Graph(v); // special case if (v == 1) return g; // Cayley's theorem: there are V^(V-2) labeled trees on V vertices // Prufer sequence: sequence of V-2 values between 0 and V-1 // Prufer's proof of Cayley's theorem: Prufer sequences are in 1-1 // with labeled trees on V vertices var prufer = new int[v - 2]; for (var i = 0; i < v - 2; i++) prufer[i] = StdRandom.Uniform(v); // degree of vertex v = 1 + number of times it appers in Prufer sequence var degree = new int[v]; for (var vi = 0; vi < v; vi++) degree[vi] = 1; for (var i = 0; i < v - 2; i++) degree[prufer[i]]++; // pq contains all vertices of degree 1 var pq = new MinPQ<Integer>(); for (var vi = 0; vi < v; vi++) if (degree[vi] == 1) pq.Insert(vi); // repeatedly delMin() degree 1 vertex that has the minimum index for (var i = 0; i < v - 2; i++) { int vmin = pq.DelMin(); g.AddEdge(vmin, prufer[i]); degree[vmin]--; degree[prufer[i]]--; if (degree[prufer[i]] == 1) pq.Insert(prufer[i]); } g.AddEdge(pq.DelMin(), pq.DelMin()); return g; }
/// <summary> /// Returns a star graph on <tt>V</tt> vertices. /// </summary> /// <param name="v">V the number of vertices in the star</param> /// <returns>a star graph on <tt>V</tt> vertices: a single vertex connected to every other vertex</returns> public static Graph Star(int v) { if (v <= 0) throw new ArgumentException("Number of vertices must be at least 1"); var g = new Graph(v); var vertices = new int[v]; for (var i = 0; i < v; i++) vertices[i] = i; StdRandom.Shuffle(vertices); // connect vertices[0] to every other vertex for (var i = 1; i < v; i++) { g.AddEdge(vertices[0], vertices[i]); } return g; }
/// <summary> /// Returns a random simple graph containing <tt>V</tt> vertices and <tt>E</tt> edges. /// </summary> /// <param name="v">V the number of vertices</param> /// <param name="e">E the number of edges</param> /// <returns> random simple graph on <tt>V</tt> vertices, containing a total of <tt>E</tt> edges</returns> /// <exception cref="ArgumentException">if no such simple graph exists</exception> public static Graph Simple(int v, int e) { if (e > (long)v * (v - 1) / 2) throw new ArgumentException("Too many edges"); if (e < 0) throw new ArgumentException("Too few edges"); var g = new Graph(v); var set = new SET<EdgeU>(); while (g.E < e) { var ve = StdRandom.Uniform(v); var we = StdRandom.Uniform(v); var edge = new EdgeU(ve, we); if ((ve == we) || set.Contains(edge)) continue; set.Add(edge); g.AddEdge(ve, we); } return g; }
/// <summary> /// Returns a uniformly random <tt>k</tt>-regular graph on <tt>V</tt> vertices /// (not necessarily simple). The graph is simple with probability only about e^(-k^2/4), /// which is tiny when k = 14. /// </summary> /// <param name="v">V the number of vertices in the graph</param> /// <param name="k"></param> /// <returns>a uniformly random <tt>k</tt>-regular graph on <tt>V</tt> vertices.</returns> public static Graph Regular(int v, int k) { if (v * k % 2 != 0) throw new ArgumentException("Number of vertices * k must be even"); var g = new Graph(v); // create k copies of each vertex var vertices = new int[v * k]; for (var vi = 0; vi < v; vi++) { for (var j = 0; j < k; j++) { vertices[vi + v * j] = vi; } } // pick a random perfect matching StdRandom.Shuffle(vertices); for (var i = 0; i < v * k / 2; i++) { g.AddEdge(vertices[2 * i], vertices[2 * i + 1]); } return g; }
/// <summary> /// Returns a path graph on <tt>V</tt> vertices. /// </summary> /// <param name="v">V the number of vertices in the path</param> /// <returns>a path graph on <tt>V</tt> vertices</returns> public static Graph Path(int v) { var g = new Graph(v); var vertices = new int[v]; for (var i = 0; i < v; i++) vertices[i] = i; StdRandom.Shuffle(vertices); for (var i = 0; i < v - 1; i++) { g.AddEdge(vertices[i], vertices[i + 1]); } return g; }
/// <summary> /// Returns an Eulerian path graph on <tt>V</tt> vertices. /// </summary> /// <param name="v">V the number of vertices in the path</param> /// <param name="e">E the number of edges in the path</param> /// <returns>a graph that is an Eulerian path on <tt>V</tt> vertices and <tt>E</tt> edges</returns> /// <exception cref="ArgumentException">if either V ≤ 0 or E < 0</exception> public static Graph EulerianPath(int v, int e) { if (e < 0) throw new ArgumentException("negative number of edges"); if (v <= 0) throw new ArgumentException("An Eulerian path must have at least one vertex"); var g = new Graph(v); var vertices = new int[e + 1]; for (var i = 0; i < e + 1; i++) vertices[i] = StdRandom.Uniform(v); for (var i = 0; i < e; i++) { g.AddEdge(vertices[i], vertices[i + 1]); } return g; }
/// <summary> /// Returns an Eulerian cycle graph on <tt>V</tt> vertices. /// </summary> /// <param name="v">V the number of vertices in the cycle</param> /// <param name="e">E the number of edges in the cycle</param> /// <returns>a graph that is an Eulerian cycle on <tt>V</tt> vertices and <tt>E</tt> edges</returns> /// <exception cref="ArgumentException">if either V ≤ 0 or E ≤ 0</exception> public static Graph EulerianCycle(int v, int e) { if (e <= 0) throw new ArgumentException("An Eulerian cycle must have at least one edge"); if (v <= 0) throw new ArgumentException("An Eulerian cycle must have at least one vertex"); var g = new Graph(v); var vertices = new int[e]; for (var i = 0; i < e; i++) vertices[i] = StdRandom.Uniform(v); for (var i = 0; i < e - 1; i++) { g.AddEdge(vertices[i], vertices[i + 1]); } g.AddEdge(vertices[e - 1], vertices[0]); return g; }
/// <summary> /// Determines whether a digraph has an Eulerian path using necessary /// and sufficient conditions (without computing the path itself): /// - indegree(v) = outdegree(v) for every vertex, /// except one vertex v may have outdegree(v) = indegree(v) + 1 /// (and one vertex v may have indegree(v) = outdegree(v) + 1) /// - the graph is connected, when viewed as an undirected graph /// (ignoring isolated vertices) /// This method is solely for unit testing. /// </summary> /// <param name="g"></param> /// <returns></returns> private static bool HasEulerianPath(Digraph g) { if (g.E == 0) return true; // Condition 1: indegree(v) == outdegree(v) for every vertex, // except one vertex may have outdegree(v) = indegree(v) + 1 var deficit = 0; for (var v = 0; v < g.V; v++) if (g.Outdegree(v) > g.Indegree(v)) deficit += (g.Outdegree(v) - g.Indegree(v)); if (deficit > 1) return false; // Condition 2: graph is connected, ignoring isolated vertices var h = new Graph(g.V); for (var v = 0; v < g.V; v++) foreach (int w in g.Adj(v)) h.AddEdge(v, w); // check that all non-isolated vertices are connected var s = NonIsolatedVertex(g); var bfs = new BreadthFirstPaths(h, s); for (var v = 0; v < g.V; v++) if (h.Degree(v) > 0 && !bfs.HasPathTo(v)) return false; return true; }
/// <summary> /// Returns a random simple graph on <tt>V</tt> vertices, with an /// edge between any two vertices with probability <tt>p</tt>. This is sometimes /// referred to as the Erdos-Renyi random graph model. /// </summary> /// <param name="v">V the number of vertices</param> /// <param name="p">p the probability of choosing an edge</param> /// <returns>a random simple graph on <tt>V</tt> vertices, with an edge between any two vertices with probability <tt>p</tt></returns> /// <exception cref="ArgumentException">if probability is not between 0 and 1</exception> public static Graph Simple(int v, double p) { if (p < 0.0 || p > 1.0) throw new ArgumentException("Probability must be between 0 and 1"); var g = new Graph(v); for (var vi = 0; vi < v; vi++) for (var wi = vi + 1; wi < v; wi++) if (StdRandom.Bernoulli(p)) g.AddEdge(vi, wi); return g; }