public void AddBranch(TreeBranch branch) { // A node can only support three connections if (branches.Count == 3) { throw new OverflowException("This node already has 3 connections."); } else { // If the branch being added connects this node to a leaf, and one of the other branches also // connects to a leaf, this is a terminal node. Add this node to the list of terminal nodes. if (branch.Follow(this).GetType() == typeof(TreeLeaf)) { foreach (TreeBranch otherBranch in branches) { if (otherBranch.Follow(this).GetType() == typeof(TreeLeaf)) { tree.terminalNodesList.Add(this); } } } branches.Add(branch); } }
public void RemoveBranch(TreeBranch branch) { // List's Remove method handles low-count and not-in-list conditions, // so I won't handle them here. // bool removeFlag = branches.Remove(branch); Not sure why I need the return code. branches.Remove(branch); if (childBranch1 == branch) { childBranch1 = null; } else if (childBranch2 == branch) { childBranch2 = null; } //if (!removeFlag) //{ // return false; //} if (parentBranch == branch) { RemoveParent(); } // If the branch removal results in no connections, the node can be removed from the tree. if (branches.Count == 0) { tree.nodesList.Remove(this); } else if (true) { // If the branch was a terminal node and the branch being removed was connected to a leaf, // if only one other branch is connected to a leaf, this is no longer a terminal node. // Remove this node from the list of terminal nodes. if (branch.Follow(this).GetType() == typeof(TreeLeaf)) { int leafCount = 0; foreach (TreeBranch otherBranch in branches) { if (otherBranch.Follow(this).GetType() == typeof(TreeLeaf)) { leafCount += 1; } } if (leafCount <= 1) { tree.terminalNodesList.Remove(this); } } } //return true; }
void AssertPaternity() // For each branch out from the given root which is not a parent branch, assign that branch // as the child's parent branch. // As this could be deeply recursive and could result in a stack overflow, this must be coded as a loop. { Stack <Tuple <TreeMember, TreeBranch> > arguments = new Stack <Tuple <TreeMember, TreeBranch> >(); TreeBranch prevBranch = new TreeBranch(); bool stepBack = false; foreach (TreeBranch rootBranch in root.Branches) { arguments.Push(Tuple.Create(rootBranch.Follow(root), rootBranch)); while (arguments.Count > 0) { Tuple <TreeMember, TreeBranch> nextArgument = arguments.Peek(); TreeMember member = nextArgument.Item1; TreeBranch parentBranch = nextArgument.Item2; stepBack = false; member.parentBranch = parentBranch; ((TreeNode)parentBranch.Follow(member)).SetChild(parentBranch); if (member.GetType() == typeof(TreeNode)) { TreeNode node = (TreeNode)member; if (node.Branches.Contains(prevBranch)) // If the previously-used branch is a member of this node's branches, that means we've already used the // branches of this node, and can discard it. { stepBack = true; } else { foreach (TreeBranch branch in node.Branches) { if (branch != parentBranch) { arguments.Push(Tuple.Create(branch.Follow(node), branch)); } } } } else { stepBack = true; } if (stepBack) { prevBranch = parentBranch; arguments.Pop(); } } } }
public TreeNode GetParent() { if (parentBranch != null) { return((TreeNode)parentBranch.Follow(this)); } else { return(null); } }
void CountNodeChildren() // Walk the tree up from the terminal nodes and count the children of each node. { if (!isRooted) { throw new InvalidOperationException("The tree must be rooted to count children."); } foreach (TreeNode terminalNode in terminalNodesList) { terminalNode.childCount = 2; TreeNode currentNode = terminalNode; while (currentNode != root) { TreeBranch parentBranch = currentNode.parentBranch; TreeNode parentNode = (TreeNode)parentBranch.Follow(currentNode); TreeBranch otherChildBranch; if (parentNode.childBranch1 == parentBranch) { otherChildBranch = parentNode.childBranch2; } else // should be childBranch2 { otherChildBranch = parentNode.childBranch1; } if (otherChildBranch.Follow(parentNode).GetType() == typeof(TreeLeaf)) { parentNode.childCount = currentNode.childCount + 1; } else if (parentNode.childCount > 0) { parentNode.childCount += currentNode.childCount; } else { // Need to wait for another terminal node to propogate up. parentNode.childCount += currentNode.childCount; break; } currentNode = parentNode; } } }
static double GetSumBranchLength(TreeMember member, TreeBranch baseBranch, bool includeBranch, out int numLeaves) // This is a recursive function // { // Algorithm: // 1. Store the branch length to the current member in "distance" (except the first if includeBranch is true). // 2. If the current member is a node, add the other branches to the stack and continue the loop. // If the current member is a leaf, add 1 to the number of leaves, add the stemLength to the sumBranchLength, and subtract the length to this branch from the distance. // 3. double sumBranchLength = 0; numLeaves = 0; Stack <Tuple <TreeMember, TreeBranch> > arguments = new Stack <Tuple <TreeMember, TreeBranch> >(); double distance = 0; arguments.Push(Tuple.Create(baseBranch.Follow(member), baseBranch)); TreeBranch prevBranch = new TreeBranch(); bool stepBack = false; while (arguments.Count > 0) { Tuple <TreeMember, TreeBranch> nextArgument = arguments.Peek(); TreeMember nextMember = nextArgument.Item1; TreeBranch nextBaseBranch = nextArgument.Item2; if (nextMember.GetType() == typeof(TreeNode)) { TreeNode node = (TreeNode)nextMember; if (node.Branches.Contains(prevBranch)) // If the previously-used branch is a member of this node's branches, that means we've already used the // branches of this node, and can discard it. { stepBack = true; } else { distance += nextBaseBranch.BranchLength; foreach (TreeBranch branch in node.Branches) { if (branch != nextBaseBranch) { arguments.Push(Tuple.Create(branch.Follow(node), branch)); } } } } else // This is a leaf, so add the distance to the sum, increment the leaf count, and step backward { distance += nextBaseBranch.BranchLength; sumBranchLength += distance; numLeaves++; stepBack = true; } if (stepBack) { prevBranch = nextBaseBranch; distance -= nextBaseBranch.BranchLength; arguments.Pop(); stepBack = false; } } if (!includeBranch) { // If we didn't want to include the base branch length, correct for that here. sumBranchLength -= numLeaves * baseBranch.BranchLength; } return(sumBranchLength); }
void DetermineSteps() // Determine the groups to be used in each step of the alignment. // Step through the tree to find the terminal leaf-only nodes and step back to join them together, // with each step stored in a tuple, and the leaf groups 1 and 2 stored in lists in members 1 and 2 of the // tuple, respectively. // Possible to parallelize, but it looks like the overhead is generally too much for the work being done. // may want to test that on larger sets, however. { if (!isRooted) { throw new InvalidOperationException("The tree must be rooted to determine alignment steps."); } Dictionary <TreeNode, List <TreeLeaf> > waitingList = new Dictionary <TreeNode, List <TreeLeaf> >(); // Store the members of one child of the node until the other child has been evaluated. steps = new List <Tuple <ReadOnlyCollection <T>, ReadOnlyCollection <T>, double> >(); foreach (TreeNode terminalNode in terminalNodesList) { List <TreeLeaf> group1 = new List <TreeLeaf>(); TreeLeaf leaf1 = (TreeLeaf)terminalNode.childBranch1.Follow(terminalNode); group1.Add(leaf1); List <TreeLeaf> group2 = new List <TreeLeaf>(); TreeLeaf leaf2 = (TreeLeaf)terminalNode.childBranch2.Follow(terminalNode); group2.Add(leaf2); steps.Add(CreateStep(group1, group2)); TreeNode currentNode = terminalNode; List <TreeLeaf> childLeaves = new List <TreeLeaf>(); childLeaves.Add(leaf1); childLeaves.Add(leaf2); while (currentNode != root) { TreeBranch parentBranch = currentNode.parentBranch; TreeNode parentNode = (TreeNode)parentBranch.Follow(currentNode); TreeBranch otherChildBranch; group1 = new List <TreeLeaf>(); group2 = new List <TreeLeaf>(); if (parentNode.childBranch1 == parentBranch) { otherChildBranch = parentNode.childBranch2; } else // should be childBranch2 { otherChildBranch = parentNode.childBranch1; } if (otherChildBranch.Follow(parentNode).GetType() == typeof(TreeLeaf)) // The other child is a leaf, so we're okay. { group1 = childLeaves; TreeLeaf otherChildLeaf = (TreeLeaf)otherChildBranch.Follow(parentNode); group2.Add(otherChildLeaf); } else if (waitingList.ContainsKey(parentNode)) // The other child is a node which was waiting for the other children to be evaluated. { group1 = childLeaves.ToList <TreeLeaf>(); group2 = waitingList[parentNode]; } else // The other child is a node. We'll need to save the current child and store the values // for later. This also means we need to start over with another terminal node. { waitingList.Add(parentNode, childLeaves); break; } steps.Add(CreateStep(group1, group2)); foreach (TreeLeaf leaf in group2) { childLeaves.Add(leaf); } currentNode = parentNode; } } }
public void CalculateSimilarities() // Construct a similarities matrix // Clustal does this by storing the path to root for each leaf (storing the distance), then finds the common ancestor // for each pair, storing the distance from the other sequence to it. // // I think a better implementation would be to loop over the leaves to get their paths to root, then for each pair, // walk their paths until they diverge { similarityMatrix = new double[leavesCount, leavesCount]; Dictionary <TreeLeaf, List <Tuple <TreeNode, double> > > pathsToRoot = new Dictionary <TreeLeaf, List <Tuple <TreeNode, double> > >(); foreach (TreeLeaf leaf in leavesList) { List <Tuple <TreeNode, double> > pathToRoot = new List <Tuple <TreeNode, double> >(); double distance = 0; TreeBranch parentBranch = leaf.parentBranch; TreeNode parentNode = (TreeNode)parentBranch.Follow(leaf); while (true) { distance += parentBranch.BranchLength; pathToRoot.Add(Tuple.Create(parentNode, distance)); parentBranch = parentNode.parentBranch; if (parentBranch != null) { parentNode = (TreeNode)parentBranch.Follow(parentNode); } else { break; } } pathsToRoot.Add(leaf, pathToRoot); } for (int i = 0; i < leavesCount - 1; i++) { TreeLeaf leafI = leavesList[i]; List <Tuple <TreeNode, double> > pathToRootI = pathsToRoot[leafI]; for (int j = i + 1; j < leavesCount; j++) { TreeLeaf leafJ = leavesList[j]; List <Tuple <TreeNode, double> > pathToRootJ = pathsToRoot[leafJ]; bool found = false; foreach (Tuple <TreeNode, double> pathMemberI in pathToRootI) { foreach (Tuple <TreeNode, double> pathmemberJ in pathToRootJ) { if (pathMemberI.Item1 == pathmemberJ.Item1) { found = true; similarityMatrix[i, j] = 1 - (pathMemberI.Item2 + pathmemberJ.Item2); break; } } if (found) { break; } } } } // Then Clustal forces any values less than 0.01 to be 0.01 (within the sequence ranges) // and sets small values above 1 to 1, but values above 1.1 go into an error handling method. // I won't implement this yet. Note that this is done while they are still in distances, not // similarities. }