Пример #1
0
        /// <summary>
        /// Find the connected components in the subtree
        /// </summary>
        /// <returns></returns>
        private List <List <Node> > FindConnectedComponents()
        {
            List <List <Node> > connectedComponents = new List <List <Node> >();
            List <Node>         subNodes            = splitNode.AllNodesInSubtree;

            subNodes.Remove(splitNode.Value);
            HashSet <Node> beenList = new HashSet <Node>(splitNode.AncestorNodes)
            {
                splitNode.Value
            };

            // Use DFS to find all connected components
            for (int i = 0; i < subNodes.Count; i++)
            {
                if (beenList.Contains(subNodes[i]))
                {
                    continue;
                }
                List <Node> connectedNodes = DFS.All(subNodes[i], (n) =>
                {
                    // When a node is explored, add the index of the component it is in to the dictionary
                    componentIndices[n] = connectedComponents.Count;
                    return(true);
                }, beenList);
                connectedComponents.Add(connectedNodes);
            }
            return(connectedComponents);
        }
Пример #2
0
        public override void Apply()
        {
            // Find all the connected components in this subtree
            List <List <Node> > connectedComponents = FindConnectedComponents();

            // If the number of connected components is equal to the number of children, we cannot split the tree even further, so return
            if (connectedComponents.Count == splitNode.Children.Count)
            {
                return;
            }

            // Consider a subtree where the middle part is a connected component. We want that part as a new child, and the rest as a new child, but connected to each other
            // Thus, if we remove the middle part of a connected component, we want to reconnect this component
            // In each component, find the new children of the splitnode, and possibly new parents for nodes that were cut off
            bool[] foundComponent = new bool[connectedComponents.Count];
            List <Tuple <RecursiveTree <Node>, RecursiveTree <Node> > > newParents = new List <Tuple <RecursiveTree <Node>, RecursiveTree <Node> > >();
            List <RecursiveTree <Node> > newChildren = DFS.All(splitNode, (n) =>
            {
                if (n == splitNode)
                {
                    return(false);
                }
                int index = componentIndices[n.Value];
                if (foundComponent[index])
                {
                    // If we have already found this component, find the first parent that is also part of this component. This node is now namely divided from the rest of this component
                    RecursiveTree <Node> parent = n.Parent;
                    while (componentIndices[parent.Value] != index)
                    {
                        parent = parent.Parent;
                    }
                    newParents.Add(new Tuple <RecursiveTree <Node>, RecursiveTree <Node> >(n, parent));
                    return(false);
                }
                foundComponent[index] = true;
                return(true);
            });

            // Reconnect the divided components
            foreach (Tuple <RecursiveTree <Node>, RecursiveTree <Node> > nodePair in newParents)
            {
                operations.Push(new RemoveChildOperation(nodePair.Item1.Parent, nodePair.Item1));
                operations.Push(new ChangeParentOperation(nodePair.Item1, nodePair.Item2));
                operations.Push(new AddChildOperation(nodePair.Item2, nodePair.Item1));
            }

            // Connect the new children to the split node
            foreach (RecursiveTree <Node> newChild in newChildren)
            {
                if (newChild.Parent == splitNode)
                {
                    continue;
                }
                operations.Push(new RemoveChildOperation(newChild.Parent, newChild));
                operations.Push(new ChangeParentOperation(newChild, splitNode));
                operations.Push(new AddChildOperation(splitNode, newChild));
            }
        }
Пример #3
0
        /// <summary>
        /// Compute the connected components in a set of nodes and fills these in the list connectedComponents
        /// </summary>
        /// <param name="nodes">All nodes in the entire tree</param>
        /// <param name="ancestors">The list of ancestors for the current subtree</param>
        /// <param name="selectedNode">The node that is the root of the current subtree</param>
        /// <param name="left">The INCLUSIVE index in nodes where the current subtree starts</param>
        /// <param name="right">The EXCLUSIVE index in nodes where the current subtree ends</param>
        private void ComputeConnectedComponents(Node[] nodes, HashSet <Node> ancestors, Node selectedNode, int left, int right)
        {
            ancestors.Add(selectedNode);
            beenList.Clear();
            beenList.UnionWith(ancestors);
            connectedComponents.Clear();

            // For all nodes in the current subtree, do a DFS to find the connected components
            for (int i = left; i < right; i++)
            {
                if (beenList.Contains(nodes[i]))
                {
                    continue;
                }
                List <Node> connectedNodes = DFS.All(nodes[i], node => { return(true); }, beenList);
                connectedComponents.Add(connectedNodes);
            }
        }
Пример #4
0
        /// <summary>
        /// Recursive method for calculating the best heuristic tree
        /// </summary>
        /// <param name="bestFoundSolution">The optimal solution thus far from this level of the tree, used for early stopping</param>
        /// <param name="nodes">A list of all nodes in this subtree</param>
        /// <param name="ancestors">The list of all ancestors of the current subtree</param>
        /// <param name="checkedSubsets">A dictionary with checked subsets, used for memoization</param>
        /// <returns>The optimal exact tree for the list of input nodes</returns>
        private RecursiveTree <Node> RecGetBestTree(int bestFoundSolution, List <Node> nodes, HashSet <Node> ancestors, Dictionary <string, RecursiveTree <Node> > checkedSubsets)
        {
            // If the currently best found solution is smaller than the list of ancestors here, we cannot possibly improve it. Thus, we return an empty tree
            if (bestFoundSolution < ancestors.Count + 1)
            {
                return(null);
            }

            // Check if we have already computed a subtree for this set of nodes, if so, return that tree
            string asBits = NodeSubsetRepresentation(nodes);

            if (checkedSubsets.ContainsKey(asBits) && checkedSubsets[asBits] != null)
            {
                RecursiveTree <Node> computedTree = new RecursiveTree <Node>(checkedSubsets[asBits]);
                return(computedTree);
            }

            // Sort the nodes on their remaining degree value (descending) and recursively compute the best trees
            HashSet <Node> nodesAsHash = new HashSet <Node>(nodes);

            nodes = nodes.OrderByDescending(n => n.RemainingDegree(nodesAsHash)).ToList();
            RecursiveTree <Node> bestTree = null;

            foreach (Node selectedNode in nodes)
            {
                RecursiveTree <Node> newTree  = new RecursiveTree <Node>(selectedNode);
                HashSet <Node>       beenList = new HashSet <Node>(ancestors)
                {
                    selectedNode
                };
                bool broken = false;

                foreach (Node n in nodes)
                {
                    // Find the connected component this node is in
                    if (beenList.Contains(n))
                    {
                        continue;
                    }
                    List <Node>    connectedNodes = DFS.All(n, (nn) => { return(true); }, beenList);
                    HashSet <Node> newHash        = new HashSet <Node>(ancestors)
                    {
                        selectedNode
                    };

                    // Compute the best possible subtree for this connected component
                    RecursiveTree <Node> ChildTree = RecGetBestTree(bestFoundSolution, connectedNodes, newHash, checkedSubsets);
                    if (ChildTree == null)
                    {
                        // If the resulting tree is null, it is not a viable solution
                        broken = true;
                        break;
                    }
                    ChildTree.Parent = newTree;
                    newTree.AddChild(ChildTree);
                }

                // If we found a viable solution, update the best found solution thus far
                if (!broken)
                {
                    int newDepth = newTree.Depth;
                    if (newDepth + ancestors.Count < bestFoundSolution)
                    {
                        bestFoundSolution = newDepth + ancestors.Count;
                        bestTree          = newTree;
                    }
                }
            }

            // Save the tree in the memoization dictionary and return it
            checkedSubsets[asBits] = bestTree;
            return(bestTree);
        }