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(); }