public static Graph DFSInit(Graph G) { for (int width = Math.Min(G.vertices.Count, Math.Max(2, Program.BagsList.Count > 0 ? Program.BagsList.Max((b) => b.Count) : 0)); width <= G.vertices.Count; width++) { FastGraph fastCopy = new FastGraph(G); List <int> eliminationOrder = fastCopy.DFS(width, null); if (eliminationOrder != null) // We know that width is the minimum width possible { return(G.TDFromEliminationOrder(eliminationOrder.Select((i) => fastCopy.baseVertices[i].OriginalVertex).ToList())); } } throw new Exception("DFS failed to find a solution"); }
// No more preprocessing rules apply, use branching or DP public Graph ComputeTD() { // Graph is too big and not dense enough. Try the separator technique if (vertices.Count >= 25 && edges.Count < 5 * vertices.Count) { Graph result = BranchOnSeparator(); if (result != null) { return(result); } } #if USE_DFS return(FastGraph.DFSInit(this)); #else return(TreewidthDP()); #endif }
// Computes a tree decomposition using the 2^n dynamic programming algorithm // Note: since this uses longs to represent partial results, only works for graphs up to 64 vertices public Graph TreewidthDP() { // Fall back on DFS if (vertices.Count > 64) { return(FastGraph.DFSInit(this)); } List <Vertex> atTheEnd = new List <Vertex>(); // Begin by finding a maximum clique, which should be the final bag. List <List <Vertex> > cliques = new List <List <Vertex> >(); foreach (Vertex v in vertices.Keys) // Initialization: all vertices cliques of size 1 { cliques.Add(new List <Vertex>(new Vertex[] { v })); } // Enumerate all cliques for (int i = 2; i <= vertices.Count; i++) { List <List <Vertex> > newCliques = new List <List <Vertex> >(); foreach (List <Vertex> clique in cliques) // Enumerate over cliques of size i-1 { foreach (Vertex v in vertices.Keys) { if (v.Label <= clique[clique.Count - 1].Label) { continue; // Optimization: only consider cliques where the vertices are in increasing order } if (clique.All((u) => { return(edges.Contains(new Edge(u, v))); })) // Can we add the vertex (is it connected to everything else)? { // Found a new clique List <Vertex> newClique = new List <Vertex>(clique); newClique.Add(v); newCliques.Add(newClique); atTheEnd = newClique; } } } if (newCliques.Count == 0) { break; } cliques = newCliques; // Limit the number of cases considered, as we want to limit the time and don't necessarily need to consider all of them cliques.Shuffle(); cliques = cliques.Take(5000).ToList(); } int width; // We use an iterative deepening approach: we start with the smallest possible width, and increase it by 1 until we find a width that fits // This simplifies the DP somewhat for (width = Math.Min(vertices.Count - 1, Math.Max(3, Program.BagsList.Count > 0 ? Program.BagsList.Max((b) => b.Count) - 1 : 0)); width < vertices.Count; width++) { atTheEnd = DPDecompose(width, cliques[0]); if (atTheEnd != null) // We know that width is the minimum width possible { break; } } // Now compute the permutation that actually gives this width while (atTheEnd.Count < vertices.Count) { DPDecompose(width, atTheEnd); } return(TDFromEliminationOrder(atTheEnd)); }