Exemplo n.º 1
0
        void ReRoot()
        // Root an unrooted tree or adjust the root location after a rooted tree has beem modified
        {
            // Alternative algorithm:
            //   0. If the tree is already rooted, remove the root node.
            //   1. Find the average branch lengths extending from every node.
            //   2. Compute the differences using the largest branch
            //         Treat the branches as vectors leaving the node separated evenly by 120 degrees, and treat
            //         the largest branch length as the top vertical vector. Subtract the vertical components of the
            //         other two vectors from the largest to find the difference score.
            //         Since cos(60 deg) = 0.5, just multiply the other vectors' magnitudes by 0.5.
            //   3. Select the node with the smallest difference.
            //   4. Select the branch from that node with the largest average branch length.
            //      a. If two or three branches are tied, select the branch among the ties with the longest
            //         length to the next node.
            //      b. If they are still tied, arbitrarily pick the first.
            //   5. Insert the root between the identified nodes, and set the branch lengths
            //      satisfying x = (internode branch length - |difference|) / 2, where the side with the smaller average
            //      branch length is increased by the difference.
            //   6. Walk the tree from the new root to assert parent relationships as needed.

            if (isRooted)
            {
                double     branchLength;
                TreeMember connection1, connection2;
                // The root should only connect to two members
                connection1  = root.Branches[0].Follow(root);
                connection2  = root.Branches[1].Follow(root);
                branchLength = root.Branches[0].BranchLength + root.Branches[1].BranchLength;

                root.Branches[0].Destroy();
                root.Branches[1].Destroy();

                TreeBranch.Build(connection1, connection2, branchLength);
            }

            TreeMember rootConnection1, rootConnection2;

            TreeNode   minNode              = new TreeNode();
            double     minDifference        = Double.MaxValue;
            TreeBranch minNodeMaxBranch     = new TreeBranch();
            TreeBranch minNodeTiedMaxBranch = new TreeBranch();

            // Find the node with the smallest vector difference
            foreach (TreeNode node in nodesList) // parallelize?
            {
                Dictionary <TreeBranch, double> averageBranchLengths = new Dictionary <TreeBranch, double>();
                TreeBranch maxBranch              = null;
                TreeBranch tiedMaxBranch          = null;
                double     maxAverageBranchLength = 0;
                foreach (TreeBranch branch in node.Branches)
                {
                    int    numLeaves;
                    double averageBranchLength = GetAverageBranchLength(node, branch, true, out numLeaves);
                    averageBranchLengths.Add(branch, averageBranchLength);
                    if (averageBranchLength > maxAverageBranchLength)
                    {
                        maxAverageBranchLength = averageBranchLength;
                        maxBranch     = branch;
                        tiedMaxBranch = null;
                    }
                    else if (averageBranchLength == maxAverageBranchLength)
                    {
                        tiedMaxBranch = branch;
                    }
                }

                double vectorDifference = maxAverageBranchLength;
                foreach (TreeBranch branch in node.Branches)
                {
                    if (branch != maxBranch)
                    {
                        vectorDifference -= 0.5 * averageBranchLengths[branch];
                    }
                }

                if (vectorDifference < minDifference)
                {
                    minDifference        = vectorDifference;
                    minNode              = node;
                    minNodeMaxBranch     = maxBranch;
                    minNodeTiedMaxBranch = tiedMaxBranch;
                }
            }
            rootConnection1 = minNode;

            // Found the minimum node. Now we must decide which branch the root should replace.
            // In the case of ties (minDifference = 0 or minNodeTiedMaxBranch is not null), the root
            // will be placed along the longest adjacent branch. If tie isn't broken, it will be the
            // first branch used.
            TreeBranch rootBranch;

            if (minDifference == 0)
            {
                double     maxBranchLength = 0;
                TreeBranch maxBranch       = new TreeBranch();
                foreach (TreeBranch branch in minNode.Branches)
                {
                    double branchLength = branch.BranchLength;

                    if (branchLength > maxBranchLength)
                    {
                        maxBranchLength = branchLength;
                        maxBranch       = branch;
                    }
                }
                rootBranch = maxBranch;
            }
            else if (minNodeTiedMaxBranch != null)
            {
                if (minNodeMaxBranch.BranchLength >= minNodeTiedMaxBranch.BranchLength)
                {
                    rootBranch = minNodeMaxBranch;
                }
                else
                {
                    rootBranch = minNodeTiedMaxBranch;
                }
            }
            else
            {
                rootBranch = minNodeMaxBranch;
            }
            rootConnection2 = rootBranch.Follow(rootConnection1);

            // Determine the lengths of the branches that will connect to the root.
            // This is determined by the equation:
            //     Li = (Aj - Ai + (Nj * L)) / (Nj + Ni)
            // Where "i" and "j" each represent one of the root connections, L indicates length,
            // A indicates average branch length, and N indicates number of leaves.
            int    numLeaves1, numLeaves2;
            double averageBranchLength1 = GetAverageBranchLength(rootConnection1, rootBranch, false, out numLeaves1);
            double averageBranchLength2 = GetAverageBranchLength(rootConnection2, rootBranch, false, out numLeaves2);
            double branchDifference = averageBranchLength1 - averageBranchLength2;
            double rootBranchLength1, rootBranchLength2;

            if (branchDifference != 0)
            {
                rootBranchLength1 = (averageBranchLength2 - averageBranchLength1 + (numLeaves2 * rootBranch.BranchLength)) / (numLeaves1 + numLeaves2);
            }
            else
            {
                rootBranchLength1 = (numLeaves2 * rootBranch.BranchLength) / (numLeaves1 + numLeaves2);
            }
            rootBranchLength2 = rootBranch.BranchLength - rootBranchLength1;

            rootBranch.Destroy(); // Remove the branch that will be replaced by the root node.

            isRooted = true;
            root     = new TreeNode(this);
            TreeBranch.Build(root, rootConnection1, rootBranchLength1);
            TreeBranch.Build(root, rootConnection2, rootBranchLength2);

            // Now we need to walk the tree from the root to ensure that all the downstream
            // nodes have the parent assigned correctly.
            AssertPaternity();
        }