protected override double computeCost() { double maximum = Math.Max(this.SelectedNodeLeft.SubTreeWidth, this.SelectedNodeRight.SubTreeWidth), sum = this.SelectedNodeLeft.SubTreeSum + this.SelectedNodeRight.SubTreeSum; // Find the first common ancestor of a and b. DecompositionNode common = this.findCommonAncestor(this.SelectedNodeLeft, this.SelectedNodeRight); // Compute the width of the ancestors of a up to the common ancestor. this.computeWidthAncestors(this.SelectedNodeLeft, common, this.SelectedNodeRight.Set, this.SelectedNodeLeft.Set, ref maximum, ref sum); // Compute the width of the ancestors of b up to the common ancestor. this.computeWidthAncestors(this.SelectedNodeRight, common, this.SelectedNodeLeft.Set, this.SelectedNodeRight.Set, ref maximum, ref sum); // Compute the width of the first common ancestor. if (maximum < common.Width) { maximum = common.Width; } sum += common.Width; // Compute the width of the remaining common ancestors. this.computeWidthAncestors(common, null, null, null, ref maximum, ref sum); double topwidth = this.Tree.Root.Right.Width; if (common.IsRoot) { BitSet set = this.Tree.Root.Right.Set - this.SelectedNodeRight.Set | this.SelectedNodeLeft.Set; topwidth = this.Tree.WidthParameter.GetWidth(this.Tree.Graph, set); } return(DecompositionTree.ComputeCost(maximum, this.Tree.VertexCount, sum, topwidth)); }
public static string WriteResult(string inputPath, string outputDirectory, DecompositionTree[] trees, int seed, double computationTime) { Directory.CreateDirectory(outputDirectory); string graph = Path.GetFileNameWithoutExtension(inputPath); string outputPath = Path.Combine(outputDirectory, $"{graph}_{trees[0].WidthParameter.Name}_{trees.Max(tree => tree.Width).ToString("F2")}.txt"); using (StreamWriter writer = new StreamWriter(outputPath)) { writer.WriteLine($"Parameter = {trees[0].WidthParameter.Name}"); writer.WriteLine($"Seed = {seed}"); writer.WriteLine($"Graph = {graph}"); writer.WriteLine($"Seconds to construct the trees = {computationTime.ToString("F2")}"); writer.WriteLine(); writer.WriteLine("Trees: "); for (int i = 0; i < trees.Length; i++) { DecompositionTree tree = trees[i]; Console.WriteLine(" " + i); writer.WriteLine($" Tree = {tree.Root}"); writer.WriteLine($" Width of tree = {tree.Width.ToString("F3")}"); writer.WriteLine($" Cost of tree = {tree.Cost.ToString("F0")}"); writer.WriteLine(); } } return(Path.GetFullPath(outputPath)); }
/// <summary> /// Returns the index of a random node in the tree that is not the root OR the child of the root with a leaf as sibling. /// </summary> /// <param name="tree">The tree.</param> /// <param name="rng">A random number generator.</param> /// <returns>The index of a node in the tree.</returns> protected int getRandomNonRootIndex(DecompositionTree tree, Random rng) { // No operations available. if (tree.Nodes.Length <= 3) { throw new IndexOutOfRangeException("No valid index can be found in the tree."); } int index = -1; // We select neither the root, nor a child of the root if its sibling is a leaf. if (tree.Root.Left.IsLeaf) { index = 1 + rng.Next(tree.Nodes.Length - 2); } else if (tree.Root.Right.IsLeaf) { index = 1 + rng.Next(tree.Nodes.Length - 2); if (index == tree.Root.SubTreeSize - 2) { index++; } } else { index = 1 + rng.Next(tree.Nodes.Length - 1); } return(index); }
public LocalSearchGraphSolution(Graph graph, DecompositionTree tree) { this.Graph = graph; this.CurrentSolution = tree; this.BestCost = tree.Cost; this.BestWidth = tree.Width; this.PerformedOperations = new List <LocalSearchOperation>(); this.PerformedOperations.Add(new IdentityOperation(tree)); }
public override LocalSearchOperation GetRandomOperation(DecompositionTree tree, Random rng) { // No operations available. if (tree.Nodes.Length <= 3) { return(null); } // Select a random node that will be moved to a different position in the tree. int index = this.getRandomNonRootIndex(tree, rng); DecompositionNode selected = tree.Find(index); // Select a random node that will become the new sibling of the selected node. int candidateCount = tree.Nodes.Length - selected.SubTreeSize - 2, positionIndex = 1 + rng.Next(candidateCount); // We need to ensure that we do not select a node in the subtree of the selected node, nor its current parent and sibling. if (selected.Branch == Branch.Left) { // Shift it outside the range of the subtree of the selected node. if (index - selected.SubTreeSize < positionIndex && positionIndex <= index) { positionIndex += selected.SubTreeSize; } // Shift it past the sibling and the parent of the selected node. if (positionIndex == index + selected.Sibling.SubTreeSize) { positionIndex += 2; } // Shift it past the parent of the selected node. else if (positionIndex == index + selected.Sibling.SubTreeSize + 1) { positionIndex++; } } else { // Shift it past the sibling of the selected node. if (positionIndex == index - selected.SubTreeSize) { positionIndex++; } // Shift it past the parent and outside the range of the subtree of the selected node. if (index - selected.SubTreeSize < positionIndex && positionIndex <= index + 1) { positionIndex += selected.SubTreeSize + 1; } } DecompositionNode sibling = tree.Find(positionIndex); return(new MoveOperation(tree, selected, sibling)); }
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 DecompositionTree Construct(DecompositionTree tree) { DecompositionNode[] leaves = tree.Root.SubTree(TreeTraversal.ParentFirst).Where(node => node.IsLeaf).ToArray(); double[,] width = new double[tree.VertexCount, tree.VertexCount + 1]; BitSet[,] sets = new BitSet[tree.VertexCount, tree.VertexCount + 1]; for (int index = 0; index < tree.VertexCount; index++) { sets[index, 1] = leaves[index].Set; width[index, 1] = leaves[index].Width; for (int length = 2; length <= tree.VertexCount - index; length++) { sets[index, length] = sets[index, length - 1] | leaves[index + length - 1].Set; } } for (int length = 2; length <= tree.VertexCount; length++) { for (int index = 0; index <= tree.VertexCount - length; index++) { double childWidth = double.PositiveInfinity; for (int k = index + 1; k < index + length; k++) { childWidth = Math.Min(childWidth, Math.Max(width[index, k - index], width[k, length - (k - index)])); } if (childWidth > tree.Width) { width[index, length] = double.PositiveInfinity; } else { width[index, length] = Math.Max(childWidth, tree.WidthParameter.GetWidth(tree.Graph, sets[index, length])); } } } DecompositionTree result = new DecompositionTree(tree.Graph, tree.WidthParameter); int treeindex = tree.Nodes.Length - 1; this.backtrack(result, leaves, width, sets, 0, tree.VertexCount, ref treeindex); 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); }
protected DecompositionNode backtrack(DecompositionTree tree, DecompositionNode[] leaves, double[,] width, BitSet[,] sets, int index, int size, ref int treeindex) { if (size == 1) { DecompositionNode node = new DecompositionNode(leaves[index], tree); node.Index = index; tree.Nodes[index] = node; return(node); } DecompositionNode parent = new DecompositionNode(sets[index, size], treeindex--, tree); tree.Nodes[parent.Index] = parent; int split = -1; double splitwidth = double.PositiveInfinity; for (int i = index + 1; i < index + size; i++) { double max = Math.Max(width[index, i - index], width[i, size - (i - index)]); if (max <= splitwidth) { splitwidth = max; split = i; } } DecompositionNode left = this.backtrack(tree, leaves, width, sets, index, split - index, ref treeindex); DecompositionNode right = this.backtrack(tree, leaves, width, sets, split, size - (split - index), ref treeindex); tree.Attach(parent, left, Branch.Left); tree.Attach(parent, right, Branch.Right); tree.Attach(null, parent, Branch.Left); parent.UpdateWidthProperties(false); return(parent); }
/// <summary> /// Adds the vertex as leaf to the partial tree. /// </summary> /// <param name="tree">The partial tree.</param> /// <param name="vertex">The vertex that will be added.</param> /// <param name="index">The index of the vertex in the tree.</param> protected void add(DecompositionTree tree, Vertex vertex, int index) { // Create the child node. DecompositionNode child = new DecompositionNode(vertex, index, tree); tree.Nodes[index] = child; if (tree.Root == null) { tree.Attach(null, child, Branch.Left); } else { BitSet set = new BitSet(tree.Root.Set); set[vertex.Index] = true; DecompositionNode parent = new DecompositionNode(set, index + 1, tree); tree.Nodes[index + 1] = parent; tree.Attach(parent, tree.Root, Branch.Right); tree.Attach(parent, child, Branch.Left); tree.Attach(null, parent, Branch.Left); parent.UpdateWidthProperties(false); } }
/// <summary> /// Returns all neighbors in the neighborhood of the tree. /// </summary> /// <param name="tree">The decomposition tree at the center of the neighborhood.</param> /// <param name="rng">A random number generator.</param> /// <returns>The neighborhood of the tree.</returns> public abstract IEnumerable <LocalSearchOperation> Operations(DecompositionTree tree, Random rng);
public IdentityOperation(DecompositionTree tree) : base(tree) { this.cost = tree.Cost; }
public SwapOperation(DecompositionTree tree, DecompositionNode left, DecompositionNode right) : base(tree) { this.SelectedNodeLeft = left; this.SelectedNodeRight = right; }
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 LocalSearchOperation(DecompositionTree tree) { this.Tree = tree; }
protected override double computeCost() { double maximum = this.SelectedNode.SubTreeWidth, sum = this.SelectedNode.SubTreeSum, topwidth = this.Tree.Root.Right.Width; DecompositionNode common = null; if (!this.SelectedNode.Parent.Set.Intersects(this.SelectedSibling.Set)) { maximum = Math.Max(maximum, Math.Max(this.SelectedSibling.SubTreeWidth, this.OriginalSibling.SubTreeWidth)); sum += this.SelectedSibling.SubTreeSum + this.OriginalSibling.SubTreeSum; // parent double width = this.Tree.WidthParameter.GetWidth(this.Tree.Graph, this.SelectedNode.Set | this.SelectedSibling.Set); sum += width; if (width > maximum) { maximum = width; } // the common ancestor common = this.findCommonAncestor(this.SelectedNode.Parent, this.SelectedSibling); sum += common.Width; if (maximum < common.Width) { maximum = common.Width; } // update the width of the child of the root if (common.IsRoot) { BitSet set = this.Tree.Root.Right.Set; if (set.IsSupersetOf(this.SelectedNode.Set)) { set -= this.SelectedNode.Set; } else { set |= this.SelectedNode.Set; } topwidth = this.Tree.WidthParameter.GetWidth(this.Tree.Graph, set); } // ancestors of parent this.computeWidthAncestors(this.SelectedNode.Parent, common, null, this.SelectedNode.Set, ref maximum, ref sum); // ancestors of the new sibling this.computeWidthAncestors(this.SelectedSibling, common, this.SelectedNode.Set, null, ref maximum, ref sum); } else if (this.SelectedNode.Set.IsSubsetOf(this.SelectedSibling.Set)) { sum += this.OriginalSibling.SubTreeSum; if (maximum < this.OriginalSibling.SubTreeWidth) { maximum = this.OriginalSibling.SubTreeWidth; } // parent sum += this.SelectedSibling.Width; if (maximum < this.SelectedSibling.Width) { maximum = this.SelectedSibling.Width; } // the common ancestor common = this.SelectedSibling; // update the width of the child of the root. if (this.SelectedSibling.IsRoot) { topwidth = this.SelectedNode.Width; } // ancestors of parent this.computeWidthAncestors(this.SelectedNode.Parent, this.SelectedSibling.Parent, null, this.SelectedNode.Set, ref maximum, ref sum); } else // the new sibling is a descendant of the original sibling { sum += this.SelectedSibling.SubTreeSum; if (maximum < this.SelectedSibling.SubTreeWidth) { maximum = this.SelectedSibling.SubTreeWidth; } // parent double width = this.Tree.WidthParameter.GetWidth(this.Tree.Graph, this.SelectedNode.Set | this.SelectedSibling.Set); sum += width; if (maximum < width) { maximum = width; } // the common ancestor common = this.SelectedNode.Parent; // update the width of the child of the root. if (this.SelectedNode.Parent.IsRoot) { topwidth = this.OriginalSibling.Right.Set.IsSupersetOf(this.SelectedSibling.Set) ? this.OriginalSibling.Left.Width : this.OriginalSibling.Right.Width; } // ancestors of the new sibling this.computeWidthAncestors(this.SelectedSibling, this.SelectedNode.Parent, this.SelectedNode.Set, null, ref maximum, ref sum); } // common ancestors this.computeWidthAncestors(common, null, null, null, ref maximum, ref sum); return(DecompositionTree.ComputeCost(maximum, this.Tree.VertexCount, sum, topwidth)); }
public override LocalSearchOperation GetRandomOperation(DecompositionTree tree, Random rng) { return(this.Operations(tree, rng).First()); }
public override IEnumerable <LocalSearchOperation> Operations(DecompositionTree tree, Random rng) { int[] combinationcounters = new int[tree.Nodes.Length]; DecompositionNode[] leftcandidates = new DecompositionNode[tree.Nodes.Length]; DecompositionNode[][] rightcandidates = new DecompositionNode[tree.Nodes.Length][]; DecompositionNode left = null, right = null; int leftindex = 0, total = 0; foreach (var node in tree.Root.SubTree(TreeTraversal.ParentFirst)) { leftcandidates[leftindex] = node; combinationcounters[leftindex] = tree.Nodes.Length - node.SubTreeSize - 1; for (DecompositionNode ancestor = node.Parent; ancestor != null; ancestor = ancestor.Parent) { combinationcounters[leftindex]--; } total += combinationcounters[leftindex]; leftindex++; } int maximum = tree.Nodes.Length; // As long as there is a operation possible while (total > 0) { int sample = rng.Next(total) + 1, sum = 0; // Find a random left candidate. for (leftindex = 0; leftindex < maximum; leftindex++) { // Move invalid left candidates to the back. while (combinationcounters[leftindex] == 0) { maximum--; combinationcounters[leftindex] = combinationcounters[maximum]; leftcandidates[leftindex] = leftcandidates[maximum]; rightcandidates[leftindex] = rightcandidates[maximum]; if (maximum == leftindex) { break; } } sum += combinationcounters[leftindex]; if (sample <= sum) { if (combinationcounters[leftindex] == 0) { throw new InvalidOperationException(); } // Select the random left candidate. left = leftcandidates[leftindex]; DecompositionNode[] candidates = rightcandidates[leftindex]; if (candidates == null) { // Initialize the set of all right candidates. candidates = rightcandidates[leftindex] = new DecompositionNode[combinationcounters[leftindex]]; int index = 0; foreach (DecompositionNode node in left.Sibling.SubTree(TreeTraversal.ParentFirst).Skip(1)) { candidates[index++] = node; } for (DecompositionNode ancestor = left.Parent; !ancestor.IsRoot; ancestor = ancestor.Parent) { foreach (DecompositionNode node in ancestor.Sibling.SubTree(TreeTraversal.ParentFirst)) { candidates[index++] = node; } } } // Select a random position. int positionindex = rng.Next(combinationcounters[leftindex]); right = candidates[positionindex]; candidates[positionindex] = candidates[--combinationcounters[leftindex]]; total--; break; } } if (right == null) { throw new InvalidOperationException(); } yield return(new SwapOperation(tree, left, right)); } }
/// <summary> /// Returns a random neighbor in the neighborhood. /// </summary> /// <param name="tree">The decomposition tree at the center of the neighborhood.</param> /// <param name="rng">A random number generator.</param> public abstract LocalSearchOperation GetRandomOperation(DecompositionTree tree, Random rng);
// Get all operations in random order. public override IEnumerable <LocalSearchOperation> Operations(DecompositionTree tree, Random rng) { // Initialize the insertion candidate list int[] candidatecounters = new int[tree.Nodes.Length]; DecompositionNode[] insertioncandidates = new DecompositionNode[tree.Nodes.Length]; DecompositionNode[][] positioncandidates = new DecompositionNode[tree.Nodes.Length][]; DecompositionNode insertioncandidate = null, positioncandidate = null; int candidateindex = 0, total = 0; foreach (var node in tree.Root.SubTree(TreeTraversal.ParentFirst)) { insertioncandidates[candidateindex] = node; total += candidatecounters[candidateindex] = tree.Nodes.Length - node.SubTreeSize - 2; candidateindex++; } int maximum = tree.Nodes.Length; // As long as there is a operation possible while (total > 0) { int sample = rng.Next(total) + 1, sum = 0; // Find a random insertion candidate. for (candidateindex = 0; candidateindex < maximum; candidateindex++) { // Move invalid insertion candidates to the back. while (candidatecounters[candidateindex] == 0) { maximum--; candidatecounters[candidateindex] = candidatecounters[maximum]; insertioncandidates[candidateindex] = insertioncandidates[maximum]; positioncandidates[candidateindex] = positioncandidates[maximum]; if (maximum == candidateindex) { break; } } sum += candidatecounters[candidateindex]; if (sample <= sum) { if (candidatecounters[candidateindex] == 0) { throw new InvalidOperationException(); } // Select the random insertion candidate. insertioncandidate = insertioncandidates[candidateindex]; DecompositionNode[] positions = positioncandidates[candidateindex]; if (positions == null) { // Initialize the set of all candidate positions. positions = positioncandidates[candidateindex] = new DecompositionNode[candidatecounters[candidateindex]]; int index = 0; foreach (var node in insertioncandidate.Sibling.SubTree(TreeTraversal.ParentFirst).Skip(1)) { positions[index++] = node; } for (DecompositionNode ancestor = insertioncandidate.Parent; !ancestor.IsRoot; ancestor = ancestor.Parent) { foreach (DecompositionNode node in ancestor.Sibling.SubTree(TreeTraversal.ParentFirst)) { positions[index++] = node; } if (ancestor != insertioncandidate.Parent) { positions[index++] = ancestor; } } if (!insertioncandidate.Parent.IsRoot) { positions[index++] = tree.Root; } } // Select a random position. int positionindex = rng.Next(candidatecounters[candidateindex]); positioncandidate = positions[positionindex]; positions[positionindex] = positions[--candidatecounters[candidateindex]]; total--; break; } } if (positioncandidate == null) { throw new InvalidOperationException(); } yield return(new MoveOperation(tree, insertioncandidate, positioncandidate)); } }
public MoveOperation(DecompositionTree tree, DecompositionNode node, DecompositionNode sibling) : base(tree) { this.SelectedNode = node; this.SelectedSibling = sibling; this.OriginalSibling = node.Sibling; }