public void Graph_with_cycle_over_2_vertices() { g.Insert(new Edge{v = 0, w = 1}); g.Insert(new Edge{v = 1, w = 0}); var sc = new StrongComponents(g); Assert.That(sc.Count, Is.EqualTo(g.V - 1)); Assert.That(sc.StronglyReachable(0, 1), Is.True); }
public void Graph_without_cycles() { g.Insert(new Edge{v = 0, w = 1}); g.Insert(new Edge{v = 1, w = 2}); g.Insert(new Edge{v = 2, w = 3}); var sc = new StrongComponents(g); Assert.That(sc.Count, Is.EqualTo(g.V)); Assert.That(sc.StronglyReachable(0, 3), Is.False); }
/// <summary> /// Solves the 2-SAT problem and returns a possible variable assignment if it exits. /// </summary> /// <returns>The variable assignment, or null if no solution exists.</returns> public bool[] Solve() { var sc = new StrongComponents(graph); scGraph = sc.CreateGraph(); literalValue = new bool[n * 2]; for (int i = 0; i < n; i++) { if (graph.vcomp[i * 2] == graph.vcomp[i * 2 + 1]) { return(null); } } literalMap = new List <int> [scGraph.Length]; for (int i = 0; i < scGraph.Length; i++) { literalMap[i] = new List <int>(); } for (int i = 0; i < n * 2; i++) { literalMap[graph.vcomp[i]].Add(i); } visited = new bool[scGraph.Length]; conflict = new bool[scGraph.Length]; for (int i = 0; i < scGraph.Length; i++) { Dfs(i); } var var = new bool[n]; for (int i = 0; i < n; i++) { if (!literalValue[i * 2] && !literalValue[i * 2 + 1]) { return(null); } var[i] = literalValue[i * 2]; } return(var); }
public void GraphSearchTest() { // this is the example graph at http://www.codeproject.com/cs/miscctrl/quickgraph.asp Graph <BasicNode> g = new Graph <BasicNode>(); BasicNode u = new BasicNode("u"); BasicNode v = new BasicNode("v"); BasicNode w = new BasicNode("w"); BasicNode x = new BasicNode("x"); BasicNode y = new BasicNode("y"); BasicNode z = new BasicNode("z"); g.Nodes.Add(u); g.Nodes.Add(v); g.Nodes.Add(w); g.Nodes.Add(x); g.Nodes.Add(y); g.Nodes.Add(z); g.AddEdge(u, v); g.AddEdge(u, x); g.AddEdge(v, y); g.AddEdge(y, x); g.AddEdge(x, v); g.AddEdge(w, u); g.AddEdge(w, y); g.AddEdge(w, z); DepthFirstSearch <BasicNode> dfs = new DepthFirstSearch <BasicNode>(g); dfs.DiscoverNode += delegate(BasicNode node) { Console.WriteLine("discover " + node); }; dfs.FinishNode += delegate(BasicNode node) { Console.WriteLine("finish " + node); }; dfs.DiscoverEdge += delegate(Edge <BasicNode> edge) { Console.WriteLine("discover " + edge); }; dfs.TreeEdge += delegate(Edge <BasicNode> edge) { Console.WriteLine("tree edge " + edge); }; dfs.FinishTreeEdge += delegate(Edge <BasicNode> edge) { Console.WriteLine("finish tree edge " + edge); }; dfs.CrossEdge += delegate(Edge <BasicNode> edge) { Console.WriteLine("cross edge " + edge); }; dfs.BackEdge += delegate(Edge <BasicNode> edge) { Console.WriteLine("back edge " + edge); }; Console.WriteLine("dfs from u:"); dfs.SearchFrom(u); Console.WriteLine(); Console.WriteLine("dfs from w:"); dfs.SearchFrom(w); Console.WriteLine(); dfs.Clear(); Console.WriteLine("cleared dfs from w:"); dfs.SearchFrom(w); Console.WriteLine(); Console.WriteLine("bfs:"); BreadthFirstSearch <BasicNode> bfs = new BreadthFirstSearch <BasicNode>(g); IndexedProperty <BasicNode, double> distance = g.CreateNodeData <double>(Double.PositiveInfinity); bfs.DiscoverNode += delegate(BasicNode node) { Console.WriteLine("discover " + node); }; bfs.FinishNode += delegate(BasicNode node) { Console.WriteLine("finish " + node); }; bfs.TreeEdge += delegate(Edge <BasicNode> edge) { Console.WriteLine("tree edge " + edge); distance[edge.Target] = distance[edge.Source] + 1; }; // compute distances from w distance[w] = 0; bfs.SearchFrom(w); Console.WriteLine("distances from w:"); foreach (BasicNode node in g.Nodes) { Console.WriteLine("[" + node + "] " + distance[node]); } Assert.Equal(2.0, distance[x]); Console.WriteLine(); Console.WriteLine("distances from w:"); DistanceSearch <BasicNode> dists = new DistanceSearch <BasicNode>(g); dists.SetDistance += delegate(BasicNode node, int dist) { Console.WriteLine("[" + node + "] " + dist); }; dists.SearchFrom(w); Console.WriteLine(); BasicNode start = z, end; (new PseudoPeripheralSearch <BasicNode>(g)).SearchFrom(ref start, out end); Console.WriteLine("pseudo-peripheral nodes: " + start + "," + end); StrongComponents <BasicNode> scc = new StrongComponents <BasicNode>(g); int count = 0; scc.AddNode += delegate(BasicNode node) { Console.Write(" " + node); }; scc.BeginComponent += delegate() { Console.Write("["); count++; }; scc.EndComponent += delegate() { Console.Write("]"); }; Console.Write("strong components reachable from w (topological order): "); scc.SearchFrom(w); Assert.Equal(4, count); Console.WriteLine(); count = 0; StrongComponents2 <BasicNode> scc2 = new StrongComponents2 <BasicNode>(g); scc2.AddNode += delegate(BasicNode node) { Console.Write(" " + node); }; scc2.BeginComponent += delegate() { Console.Write("["); count++; }; scc2.EndComponent += delegate() { Console.Write("]"); }; Console.Write("strong components reachable from w (rev topological order): "); scc2.SearchFrom(w); Assert.Equal(4, count); Console.WriteLine(); #if false Console.WriteLine("CyclicDependencySort:"); List <BasicNode> schedule = CyclicDependencySort <BasicNode> .Schedule(g, delegate(BasicNode node, ICollection <BasicNode> available) { if (node == x) { return(available.Contains(u)); } else { return(false); } }, g.Nodes); foreach (BasicNode node in schedule) { Console.Write(node + " "); } Console.WriteLine(); Assert.Equal <int>(6, schedule.Count); // order should be: w u x v y z (z can be re-ordered) Assert.Equal <BasicNode>(w, schedule[0]); Assert.Equal <BasicNode>(u, schedule[1]); //Assert.Equal<BasicNode>(z,schedule[5]); #endif }
private EquationDecomposition(EquationSystem eqsys) { /** This algorithm decomposes a given equation system into smaller equation blocks * which can be solved subsequently. The algorithm is sometimes referred to as * Tarjan's sorting or Dulmage-Mendelson decomposition. * * The algorithm consists of several steps. The description below will use the * following notions: * Var: The set of variables of the whole equation system * Eqn: The set of equations of the whole equation system * Var u Eqn: The set unification of Var and Eqn * * Step (1): Maximum matching * Define an undirected graph G = (V, E) with V = Var u Eqn. * Whenever an equation eqn \in Eqn references a variable var \in Var * add the edge (eqn, var) to E. * Compute a maximum matching M between variables and equations. * M will now contain a set of equation/variable pairs. * * Step (2): Finding strongly connected components * Define a directed graph Gd = (V, Ed) with V = Var u Eqn. * Whenever an equation eqn \in Eqn references a variable var \in Var * add the edge (eqn, var) to Ed. * For each equation/variable pair (eqn, var) in M add furthermore * the edge (var, eqn) to Ed. * Note: Matched equation/variable pairs will result in bi-directional edges in Ed. * Compute the strongly connected components SCC of Gd. * SCC is a set of subsets of V such that each subset represents one component. * * Step (3): Building the tree of equation blocks * Defined a directed graph Dt = (SCC, Et). * For each equation eqn \in Eqn which is assigned to component c1 and * references a variable var \in Var which is assigned to component c2 * add an edge (c1, c2) to Et of c1 and c2 are different. * * The resulting graph will have a tree/forest sutrcture. Each node * represents an equation block. An edge b1 -> b2 represents a dependency in the * that b2 must be solved prior to b1. A schedule can be found by topological * sorting the tree. * */ if (eqsys == null || eqsys.Equations == null || eqsys.Variables == null) { throw new ArgumentException("null reference in equation system argument"); } if (eqsys.Equations.Count != eqsys.Variables.Count) { throw new ArgumentException("equation system is not well-constrained!"); } /** Assign each equation and each variable an index which will be a unique node * ID within the graphs. Indices are assigned as follows: * - Equations get indices from 0...count(equations)-1 * - Variables get indices from count(equations)...count(equations)+count(variables) * Note: Assuming a well-constrained equation system, count(equations) = count(variables) **/ int curidx = 0; foreach (Expression eq in eqsys.Equations) { eq.Cookie = curidx++; } Dictionary <object, int> idx = new Dictionary <object, int>(); foreach (Variable v in eqsys.Variables) { idx[v] = curidx++; } // Steps 1 and 2: Construct G and Gd Graph g = new Graph(curidx); Digraph dg = new Digraph(curidx); for (int i = 0; i < eqsys.Equations.Count; i++) { Expression eq = eqsys.Equations[i]; LiteralReference[] lrs = eq.ExtractLiteralReferences(); foreach (LiteralReference lr in lrs) { int j; if (idx.TryGetValue(lr.ReferencedObject, out j)) { g.AddEdge(i, j); dg.AddEdge(i, j); } } } // Step 1: Maximum matching GraphAlgorithms.Matching m = g.GetMaximumMatching(); bool success = m.IsMaximumCardinality; for (int i = 0; i < eqsys.Equations.Count; i++) { int k = m[i]; if (k >= 0) { dg.AddEdge(k, i); } } // Step 2: Strongly connected components StrongComponents sc = dg.GetStrongComponents(); int numc = sc.NumComponents; EquationBlock[] blocks = new EquationBlock[numc]; for (int i = 0; i < numc; i++) { blocks[i] = new EquationBlock(); } // Step 3: Construct the tree Digraph dg2 = new Digraph(numc); for (int i = 0; i < eqsys.Equations.Count; i++) { int c = sc[i]; blocks[c].EqSys.Equations.Add(eqsys.Equations[i]); int vi = m[i]; Variable v = eqsys.Variables[vi - eqsys.Equations.Count]; blocks[c].EqSys.Variables.Add(v); List <int> outset = dg.GetOutSet(i); foreach (int ovi in outset) { int oc = sc[ovi]; if (c != oc) { dg2.AddEdge(c, oc); } } } List <int> rootSet = new List <int>(); List <int> sinkSet = new List <int>(); for (int c = 0; c < numc; c++) { if (dg2.GetOutDegree(c) == 0) { rootSet.Add(c); } if (dg2.GetInDegree(c) == 0) { sinkSet.Add(c); } List <int> outset = dg2.GetOutSet(c); foreach (int oc in outset) { blocks[c].Predecessors.Add(blocks[oc]); } List <int> inset = dg2.GetInSet(c); foreach (int ic in inset) { blocks[c].Successors.Add(blocks[ic]); } } RootSet = (from int c in rootSet select blocks[c]).ToArray(); SinkSet = (from int c in sinkSet select blocks[c]).ToArray(); AllBlocks = blocks; }