// Removes a separator from the graph, and recursively computes a tree decomposition. The separator should be safe. // If check3isolated is true, then this also checks the property that given a separator of size 3, it should not split off any isolated vertices (or else it is not safe). // If any connected component has more than maximumSize vertices, do not proceed (balanced separator check) public Graph RemoveSeparator(List <Vertex> separator, bool check3isolated, int maximumSize) { // Compute the graph after removing separator List <Vertex> tempVertices = vertices.Keys.ToList(); foreach (Vertex v in separator) { tempVertices.Remove(v); } // Get the connected components Graph componentsGraph = new Graph(tempVertices); List <List <Vertex> > components = componentsGraph.getComponents(); // If applicable, check that it is safe if (check3isolated && components.Any((c) => c.Count == 1)) { return(null); } // Check balance if (components.Any((c) => c.Count > maximumSize)) { return(null); } // Prepare the new tree decomposition: the root bag contains the separator Graph result = new Graph(); Program.BagsList.Add(new List <Vertex>(separator)); Vertex root = result.AddVertex(Program.BagsList.Count - 1); // Decompose each component foreach (List <Vertex> component in components) { // Create a new graph with the component in it Graph componentGraph = new Graph(component); // Add the separator foreach (Vertex v in separator) { componentGraph.AddVertex(v); } foreach (Vertex u in separator) { // Make the separator a clique foreach (Vertex v in separator) { if (u.Label <= v.Label) // Not strictly necessary, but might save some time { continue; } componentGraph.AddEdge(u, v); } // And add edges from the separator to the rest foreach (Vertex v in u.Adj) { componentGraph.AddEdge(u, v); } } // Compute the TD of the component Graph TDComponent = componentGraph.Decompose(); result.AddGraph(TDComponent); // Find an appropriate bag in the decomposition to connect our root bag to foreach (Vertex v in TDComponent.vertices.Keys) { if (separator.All((u) => { return(Program.BagsList[v.Label].Contains(u)); })) { result.AddEdge(root, v); break; } } } return(result); }
// Uses DP to find a decomposition with bag size at most upper public List <Vertex> DPDecompose(int upper, List <Vertex> atTheEnd) { // Make a list of the original labels List <int> vertexLabels = new List <int>(); foreach (Vertex v in vertices.Keys) { vertexLabels.Add(v.Label); } // Replace the labels with 0...n-1 Graph relabeledGraph = new Graph(); foreach (Vertex v in vertices.Keys) { relabeledGraph.AddVertex(vertexLabels.IndexOf(v.Label)); } // Copy the edges (using the relabeled vertices) foreach (Edge e in edges) { relabeledGraph.AddEdge(new Vertex(vertexLabels.IndexOf(e.a.Label)), new Vertex(vertexLabels.IndexOf(e.b.Label))); } // We know which vertices should go at the end List <Vertex> possibleVertices = new List <Vertex>(relabeledGraph.vertices.Keys.ToArray()); foreach (Vertex v in atTheEnd) { possibleVertices.Remove(new Vertex(vertexLabels.IndexOf(v.Label))); } // Initialize the table: just the empty set HashSet <ulong> table = new HashSet <ulong>(); table.Add(0); // Once we have processed n - upper - 1 vertices, in the next step there are only upper vertices not in S, and thus we always meet the restrictions for (int i = 0; i < Math.Min(vertices.Count - upper - 1, vertices.Count - atTheEnd.Count - 1); i++) { bool islast = i == Math.Min(vertices.Count - upper - 1, vertices.Count - atTheEnd.Count - 1) - 1; HashSet <ulong> newTable = new HashSet <ulong>(); #if SEQUENTIAL foreach (ulong S in table) { if (islast && newTable.Count > 0) { break; } // Try to add each vertex foreach (Vertex x in possibleVertices) { ulong newS = S | (1UL << x.Label); if (newS == S || Q(newS, x) > upper) { continue; // We either have already seen this vertex, or it would be too expensive } newTable.Add(newS); } } #else // Attempt to get parallelism working on the test system System.Threading.ThreadPool.SetMaxThreads(48 * 5, 48 * 5); System.Threading.ThreadPool.SetMinThreads(8, 8); Parallel.ForEach(table, () => new List <ulong>(), (S, loopState, partialResult) => { if (islast && (newTable.Count > 0 || partialResult.Count > 0)) { return(partialResult); } // Try to add each vertex foreach (Vertex x in possibleVertices) { ulong newS = S | (1UL << x.Label); if (newS == S || Q(newS, x) > upper) { continue; // We either have already seen this vertex, or it would be too expensive } partialResult.Add(newS); } return(partialResult); }, (localResult) => { lock (newTable) { foreach (ulong l in localResult) { newTable.Add(l); } } }); #endif table = newTable; Program.TotalExpanded += table.Count; } // If there are any entries in the table, we know it's feasible if (table.Count > 0) { for (int i = 0; i < vertices.Count; i++) { if ((table.First() & (1UL << i)) == 0 && !atTheEnd.Contains(vertices[new Vertex(vertexLabels[i])])) { atTheEnd.Add(vertices[new Vertex(vertexLabels[i])]); } } return(atTheEnd); } else { return(null); } }
static void HandleCase() { Stopwatch timer = new Stopwatch(); timer.Start(); // Parse the input graph Graph g = new Graph(); for (string line = Console.ReadLine(); line != null; line = Console.ReadLine()) { if (line.StartsWith("c") || line.StartsWith("n")) { continue; // Comment or dimacs node } if (line.StartsWith("p")) // Initialization { string[] cf = line.Split(' '); for (int i = 0; i < int.Parse(cf[2]); i++) { g.AddVertex(i); } continue; } // Dimacs-style edge if (line.StartsWith("e")) { string[] vt = line.Split(' '); // Edge g.AddVertex(int.Parse(vt[1]) - 1); g.AddVertex(int.Parse(vt[2]) - 1); g.AddEdge(g[int.Parse(vt[1]) - 1], g[int.Parse(vt[2]) - 1]); continue; } // Something else, possibly an edge try { string[] vt = line.Split(' '); // Edge g.AddVertex(int.Parse(vt[0]) - 1); g.AddVertex(int.Parse(vt[1]) - 1); g.AddEdge(g[int.Parse(vt[0]) - 1], g[int.Parse(vt[1]) - 1]); } catch { } } if (g.vertices.Count == 0) { Console.WriteLine("s td 0 0 0"); return; } // Run the algorithm BagsList = new List <List <Vertex> >(); TotalExpanded = 0; SeparatorTried = 0; Graph TD = g.Decompose(); int treewidth = BagsList.Max((b) => b.Count); // Write the output decomposition Console.Write("s td {0} {1} {2}", TD.vertices.Count, treewidth, g.vertices.Count); //s-line // Output bag contents int bc = 1; foreach (Vertex v in TD.vertices.Keys) { Console.WriteLine(); Console.Write("b " + bc); foreach (Vertex v2 in BagsList[v.Label]) { Console.Write(" " + (v2.Label + 1)); } v.Label = bc++; } // Output edges foreach (Edge e in TD.edges) { Console.WriteLine(); Console.Write((e.a.Label) + " " + (e.b.Label)); } timer.Stop(); //Console.Write("tw\t" + treewidth + "\texp\t" + TotalExpanded + "\ttime\t" + Math.Round(timer.ElapsedMilliseconds / 1000d, 2)); }