public override DecompositionTree Construct(Graph graph, WidthParameter widthparameter) { DecompositionTree tree = new DecompositionTree(graph, widthparameter); // Create the leaves. DecompositionNode[] nodes = new DecompositionNode[graph.Vertices.Count]; for (int i = 0; i < nodes.Length; i++) { tree.Nodes[i] = nodes[i] = new DecompositionNode(new BitSet(nodes.Length, graph.Vertices[i].Index), i, tree); } int size = nodes.Length; while (size > 1) { // Find the pair of nodes whose combination is of minimal width. double min = double.PositiveInfinity; int first = -1, second = -1; for (int i = 0; i < size; i++) { for (int j = i + 1; j < size; j++) { double width = widthparameter.GetWidth(graph, nodes[i].Set | nodes[j].Set); if (width < min) { min = width; first = i; second = j; } } } // Create the parent and connect it to its children. DecompositionNode node = new DecompositionNode(nodes[first].Set | nodes[second].Set, nodes.Length * 2 - size, tree); tree.Attach(node, nodes[first], Branch.Left); tree.Attach(node, nodes[second], Branch.Right); tree.Nodes[node.Index] = node; // Update the active set of nodes. nodes[first] = node; nodes[second] = nodes[size - 1]; size--; } tree.Attach(null, nodes[0], Branch.Left); tree.ComputeWidth(); return(tree); }
/// <summary> /// Construct a linear decomposition tree from the given starting vertex. /// </summary> protected DecompositionTree construct(Graph graph, WidthParameter widthparameter, Vertex start) { DecompositionTree result = new DecompositionTree(graph, widthparameter); int index = 0; BitSet leftbits = new BitSet(graph.Vertices.Count, start.Index); BitSet rightbits = ~leftbits; BitSet neighborhood = new BitSet(start.Neighborhood); this.add(result, start, index++); while (!rightbits.IsEmpty) { Vertex selected = null; double best = double.PositiveInfinity; var candidates = this.candidates(graph, rightbits, leftbits, neighborhood); foreach (var candidate in candidates) { BitSet left = new BitSet(leftbits); left[candidate.Index] = true; BitSet right = new BitSet(rightbits); right[candidate.Index] = false; double width = widthparameter.GetWidth(graph, left, right); if (width < best) { best = width; selected = candidate; } } leftbits[selected.Index] = true; rightbits[selected.Index] = false; neighborhood.Or(selected.Neighborhood); neighborhood[selected.Index] = false; this.add(result, selected, index); index += 2; } return(result); }
public override DecompositionTree Construct(Graph graph, WidthParameter widthparameter) { DecompositionTree tree = new DecompositionTree(graph, widthparameter); // Create the leaves. DecompositionNode[] nodes = new DecompositionNode[graph.Vertices.Count]; for (int i = 0; i < nodes.Length; i++) { tree.Nodes[i] = nodes[i] = new DecompositionNode(new BitSet(nodes.Length, graph.Vertices[i].Index), i, tree); } int size = nodes.Length; while (size > 1) { int first = this.rng.Next(size); int second = this.rng.Next(size - 1); if (second <= first) { second++; } // Create the parent and connect it to its children. DecompositionNode node = new DecompositionNode(nodes[first].Set | nodes[second].Set, nodes.Length * 2 - size, tree); tree.Attach(node, nodes[first], Branch.Left); tree.Attach(node, nodes[second], Branch.Right); tree.Nodes[node.Index] = node; // Update the active set of nodes. nodes[first] = node; nodes[second] = nodes[size - 1]; size--; } tree.Attach(null, nodes[0], Branch.Left); tree.ComputeWidth(); return(tree); }
/// <summary> /// Construct a decomposition tree from the graph. /// </summary> /// <param name="graph">The graph that will be decomposed.</param> /// <param name="widthparameter">The width-parameter used to create the decomposition.</param> /// <returns>A binary decomposition tree of the graph.</returns> public abstract DecompositionTree Construct(Graph graph, WidthParameter widthparameter);
public static void RunUserTest() { Console.WriteLine("Path to graph file? Defaults to the anna graph from the TreewidthLIB set."); string pathToGraph = Console.ReadLine(); if (pathToGraph.Length == 0) { pathToGraph = @"..\..\ExampleGraphs\anna.dgf"; } Graph graph = Parser.ParseGraphFromDGF(pathToGraph); Console.WriteLine("Width Parameter is (M)aximum-matching, (R)ank or (B)oolean? Defaults to rank-width."); WidthParameter width = null; string widthParameterString = Console.ReadLine().ToLower(); if (widthParameterString.Length == 0) { width = new RankWidth(); } else { switch (widthParameterString.ToLower()[0]) { case 'm': width = new MaximumMatchingWidth(); break; case 'b': width = new BooleanWidth(); break; default: width = new RankWidth(); break; } } Console.WriteLine("Local search duration in seconds? Defaults to 60 seconds."); int localSearchDuration = 0; if (!int.TryParse(Console.ReadLine(), out localSearchDuration)) { localSearchDuration = 60; } Console.WriteLine("Seed for the random number generator? Defaults to a random seed."); int seed = -1; if (!int.TryParse(Console.ReadLine(), out seed)) { Random r = new Random(); seed = r.Next(); Console.WriteLine("Seed is " + seed); } Random rng = new Random(seed); Console.WriteLine("Should reduction rules be applied, (Y)es or (N)o? Defaults to yes."); string reductionString = Console.ReadLine().ToLower(); bool useReductionRules = reductionString.Length == 0 || reductionString[0] != 'n'; double totalseconds = 0; Console.WriteLine(); Console.WriteLine("---------------------- Starting -----------------------"); Console.WriteLine(); Graph[] graphs = null; if (useReductionRules) { int originalvertexcount = graph.Vertices.Count; Console.WriteLine($"Graph {Path.GetFileNameWithoutExtension(pathToGraph)} consists of {originalvertexcount} vertices."); Console.WriteLine($"Applying the reduction rules..."); graphs = width.ApplyReductionRules(graph); Console.WriteLine($"Number of vertices removed by the reduction rules = {originalvertexcount - graphs.Sum(g => g.Vertices.Count)}"); Console.WriteLine($"The reduction rules splitted the graph in {graphs.Length} subgraphs of sizes {string.Join(", ", graphs.Select(g => g.Vertices.Count))}."); } else { graphs = new Graph[] { graph } }; Console.WriteLine(); Console.WriteLine("Constructing initial solution..."); Stopwatch sw = Stopwatch.StartNew(); ConstructionHeuristic constructor = new GreedyLinearConstructor(rng); DecompositionTree[] trees = graphs.Select(g => constructor.Construct(g, width)).ToArray(); sw.Stop(); totalseconds += sw.ElapsedMilliseconds / 1000.0; Console.WriteLine($"Finished construction of initial solution in {(sw.ElapsedMilliseconds / 1000).ToString("F2")} seconds."); Console.WriteLine($"Initial {width.Name} = {string.Join(", ", trees.Select(tree => tree.Width.ToString("F2")))}"); Console.WriteLine($"Initial cost = {string.Join(", ", trees.Select(tree => tree.Cost.ToString("F2")))}"); Console.WriteLine(); Console.WriteLine("Improving solution with DP..."); sw.Restart(); OptimalOrderedTree oot = new OptimalOrderedTree(); trees = trees.Select(tree => oot.Construct(tree)).ToArray(); sw.Stop(); totalseconds += sw.ElapsedMilliseconds / 1000.0; Console.WriteLine($"Finished DP in {(sw.ElapsedMilliseconds / 1000.0).ToString("F2")} seconds."); Console.WriteLine($"Resulting {width.Name} = {string.Join(", ", trees.Select(tree => tree.Width.ToString("F2")))}"); Console.WriteLine($"Resulting cost = {string.Join(", ", trees.Select(tree => tree.Cost.ToString("F2")))}"); Console.WriteLine(); Console.WriteLine("Improving solution with local search..."); LocalSearchAlgorithm localsearch = new VariableNeighborhoodSearch(trees, new LocalSearchOperator[] { new MoveOperator(), new SwapOperator() }, rng); localsearch.Run(localSearchDuration); totalseconds += localsearch.CurrentComputationTime; Console.WriteLine($"Finished local search in {localsearch.CurrentComputationTime.ToString("F2")} seconds."); Console.WriteLine($"Total iterations = {localsearch.Iterations}"); Console.WriteLine($"Explored solutions = {localsearch.ExploredSolutions}"); Console.WriteLine($"Best {width.Name} = {string.Join(", ", trees.Select(tree => tree.Width.ToString("F2")))}"); Console.WriteLine($"Best cost = {string.Join(", ", trees.Select(tree => tree.Cost.ToString("F2")))}"); Console.WriteLine("Best decomposition trees:"); for (int i = 0; i < trees.Length; i++) { Console.WriteLine($"{i}: {trees[i].Root}"); } Console.WriteLine(); Console.WriteLine("Cache statistics:"); Console.WriteLine($" request count = {width.CacheRequests}"); Console.WriteLine($" hit ratio = {width.CacheHitRatio.ToString("F3")}"); Console.WriteLine(); Console.WriteLine("Write result to disk? (Y)es / (N)o, defaults to Yes."); string outputResponseString = Console.ReadLine().ToLower(); if (outputResponseString.Length == 0 || outputResponseString[0] == 'y') { Console.WriteLine("Output directory? Defaults to \\output."); string outputDirectory = Console.ReadLine(); if (outputDirectory.Length == 0) { outputDirectory = "output"; } Console.WriteLine($"Stored the result as {WriteResult(pathToGraph, outputDirectory, trees, seed, totalseconds)}"); } else { Console.ReadLine(); } }
public override DecompositionTree Construct(Graph graph, WidthParameter widthparameter) { int index = 0; DecompositionTree tree = new DecompositionTree(graph, widthparameter); DecompositionNode root = new DecompositionNode(~(new BitSet(tree.VertexCount)), index, tree); tree.Nodes[index++] = root; tree.Attach(null, root, Branch.Left); List <DecompositionNode> candidates = new List <DecompositionNode>(); candidates.Add(root); while (candidates.Count > 0) { // Select a random childless internal node. DecompositionNode parent = candidates[this.rng.Next(candidates.Count)]; candidates.Remove(parent); // Shuffle its set of vertices. int[] indices = parent.Set.ToArray(); indices.Shuffle(this.rng); // Split the set randomly into two non-empty sets. int split = 1 + this.rng.Next(indices.Length - 2); // Create its children. DecompositionNode left = null; if (split == 1) { left = new DecompositionNode(graph.Vertices[indices[0]], index, tree); } else { BitSet leftset = new BitSet(tree.VertexCount); for (int i = 0; i < split; i++) { leftset[indices[i]] = true; } left = new DecompositionNode(leftset, index, tree); candidates.Add(left); } tree.Nodes[index++] = left; tree.Attach(parent, left, Branch.Left); DecompositionNode right = null; if (split == indices.Length - 1) { right = new DecompositionNode(graph.Vertices[indices[indices.Length - 1]], index, tree); } else { BitSet rightset = new BitSet(tree.VertexCount); for (int i = split; i < indices.Length; i++) { rightset[indices[i]] = true; } right = new DecompositionNode(rightset, index, tree); candidates.Add(right); } tree.Nodes[index++] = right; tree.Attach(parent, right, Branch.Right); } tree.ComputeWidth(); return(tree); }
public override DecompositionTree Construct(Graph graph, WidthParameter widthparameter) { return(this.construct(graph, widthparameter, graph.Vertices[this.random.Next(graph.Vertices.Count)])); }
public DecompositionTree(DecompositionTree tree, WidthParameter width = null) : this(tree.Graph, width != null ? width : tree.WidthParameter) { this.Root = tree.Root.CopyTree(this, null); }
public DecompositionTree(Graph graph, WidthParameter parameter) { this.Graph = graph; this.WidthParameter = parameter; this.Nodes = new DecompositionNode[graph.Vertices.Count * 2 - 1]; }