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));
        }
Example #2
0
        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));
        }
Example #3
0
        /// <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);
        }
Example #4
0
 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));
 }
Example #5
0
        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);
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
        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);
            }
        }
Example #12
0
 /// <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);
Example #13
0
 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);
        }
Example #16
0
 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));
        }
Example #18
0
 public override LocalSearchOperation GetRandomOperation(DecompositionTree tree, Random rng)
 {
     return(this.Operations(tree, rng).First());
 }
Example #19
0
        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));
            }
        }
Example #20
0
 /// <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);
Example #21
0
        // 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;
 }