private boolean pickWide() { final int nNodesExceptRoot = nSpeciesNodes - 1; final Node rootNode = speciesTreeNodes[nNodesExceptRoot]; // pick an internal node at random (excluding the root) final int yNodeNumber = nLeafNodes + Randomizer.nextInt(nInternalNodes - 1); yNode = speciesTreeNodes[yNodeNumber]; final double yNodeHeight = yNode.getHeight(); if (Randomizer.nextBoolean()) { aNode = yNode.getLeft(); bNode = yNode.getRight(); } else { aNode = yNode.getRight(); bNode = yNode.getLeft(); } // for all internal nodes (excluding the root) final Node[] zNodes = new Node[nNodesExceptRoot]; czNodeFinder(yNode, rootNode, yNodeHeight, zNodes); // pick a cousin from the available candidates int cousinNodeNumber = Randomizer.nextInt(nNodesExceptRoot); zNode = zNodes[cousinNodeNumber]; while (zNode == null) { cousinNodeNumber = Randomizer.nextInt(nNodesExceptRoot); // System.out.println(String.format("%d/%d", cousinNodeNumber, nNodesExceptRoot)); zNode = zNodes[cousinNodeNumber]; } cNode = speciesTreeNodes[cousinNodeNumber]; return true; }
private boolean pickNarrow() { zNode = speciesTreeNodes[nLeafNodes + Randomizer.nextInt(nInternalNodes)]; while (zNode.getLeft().isLeaf() && zNode.getRight().isLeaf()) { zNode = speciesTreeNodes[nLeafNodes + Randomizer.nextInt(nInternalNodes)]; } yNode = zNode.getLeft(); cNode = zNode.getRight(); if (yNode.getHeight() < cNode.getHeight()) { yNode = zNode.getRight(); cNode = zNode.getLeft(); } if (yNode.isLeaf()) { return false; } else if (Randomizer.nextBoolean()) { aNode = yNode.getLeft(); bNode = yNode.getRight(); } else { aNode = yNode.getRight(); bNode = yNode.getLeft(); } return true; }
/** * Obtain the sister of node "child" having parent "parent". * * @param parent the parent * @param child the child that you want the sister of * @return the other child of the given parent. */ protected Node getOtherChild(Node parent, Node child) { if (parent.getLeft().getNr() == child.getNr()) { return parent.getRight(); } else { return parent.getLeft(); } }
// identify nodes that can serve as graft branches as part of a coordinated exchange move private boolean findGraftBranches( Node geneTreeNode, Set<Node> graftNodes, Set<String> branchDescendants) { if (geneTreeNode.isLeaf()) { final String descendantName = geneTreeNode.getID(); return branchDescendants.contains(descendantName); } final Node leftChild = geneTreeNode.getLeft(); final Node rightChild = geneTreeNode.getRight(); final boolean leftOverlaps = findGraftBranches(leftChild, graftNodes, branchDescendants); final boolean rightOverlaps = findGraftBranches(rightChild, graftNodes, branchDescendants); // subtree defined by a child node overlaps species subtree defined by branch if (leftOverlaps || rightOverlaps) { if (leftOverlaps) { graftNodes.add(leftChild); } if (rightOverlaps) { graftNodes.add(rightChild); } return true; } return false; }
/** * Method used by convertLengthToHeight(node) to remove negative offset from node heights that * is produced by convertLengthToHeight(node, height). * * @param node node of clade to offset * @param delta offset */ private void offset(final Node node, final double delta) { node.setHeight(node.getHeight() + delta); if (node.isLeaf()) { if (node.getHeight() < thresholdInput.get()) { node.setHeight(0); } } if (!node.isLeaf()) { offset(node.getLeft(), delta); if (node.getRight() != null) { offset(node.getRight(), delta); } } }
/** * Recursive method used to convert lengths to heights. Applied to the root, results in heights * from 0 to -total_height_of_tree. * * @param node node of a clade to convert * @param height Parent height. * @return total height of clade */ private double convertLengthToHeight(final Node node, final double height) { final double length = node.getHeight(); node.setHeight((height - length) * scaleInput.get()); if (node.isLeaf()) { return node.getHeight(); } else { final double left = convertLengthToHeight(node.getLeft(), height - length); if (node.getRight() == null) { return left; } final double right = convertLengthToHeight(node.getRight(), height - length); return Math.min(left, right); } }
private List<Integer> czNodeFinder( final Node parentNode, final Node currentNode, final double parentNodeHeight, final Node[] zNodes) { // valid graft nodes (nodes defining branches which include the height of the parent node) final List<Integer> candidateList = new ArrayList<>(); final double currentNodeHeight = currentNode.getHeight(); if (parentNode == currentNode) { return null; } else if (parentNodeHeight >= currentNodeHeight) { // this is a candidate node (would be a valid choice to graft parentNode to) candidateList.add(currentNode.getNr()); return candidateList; } else { final List<Integer> leftCandidateNodeNumbers = czNodeFinder(parentNode, currentNode.getLeft(), parentNodeHeight, zNodes); final List<Integer> rightCandidateNodeNumbers = czNodeFinder(parentNode, currentNode.getRight(), parentNodeHeight, zNodes); if (leftCandidateNodeNumbers == null) { // parent is the left child or descendant of the left child // therefore the current node is the most recent common ancestor connecting the parent and // right candidates for (final Integer candidateNodeNumber : rightCandidateNodeNumbers) { zNodes[candidateNodeNumber] = currentNode; } return null; } else if (rightCandidateNodeNumbers == null) { // parent is the right child or descendant of the right child // therefore the current node is the most recent common ancestor connecting the parent and // left candidates for (final Integer candidateNodeNumber : leftCandidateNodeNumbers) { zNodes[candidateNodeNumber] = currentNode; } return null; } else { candidateList.addAll(leftCandidateNodeNumbers); candidateList.addAll(rightCandidateNodeNumbers); return candidateList; } } }
/** * Creates a new branch between node and a new node at time destTime between destBranchBase and * its parent. Colour changes are divided between the two new branches created by the split. * * @param node * @param destBranchBase * @param destTime */ public void connectBranch(Node node, Node destBranchBase, double destTime) { // Check argument validity: if (node.isRoot() || destBranchBase.isRoot()) throw new IllegalArgumentException("Illegal argument to " + "connectBranch()."); // Obtain existing parent of node and set new time: Node parent = node.getParent(); parent.setHeight(destTime); MultiTypeNode mtParent = (MultiTypeNode) parent; MultiTypeNode mtDestBranchBase = (MultiTypeNode) destBranchBase; // Determine where the split comes in the list of colour changes // attached to destBranchBase: int split; for (split = 0; split < mtDestBranchBase.getChangeCount(); split++) if (mtDestBranchBase.getChangeTime(split) > destTime) break; // Divide colour changes between new branches: mtParent.clearChanges(); for (int idx = split; idx < mtDestBranchBase.getChangeCount(); idx++) mtParent.addChange(mtDestBranchBase.getChangeType(idx), mtDestBranchBase.getChangeTime(idx)); mtDestBranchBase.truncateChanges(split); // Set colour at split: mtParent.setNodeType(mtDestBranchBase.getFinalType()); // Implement topology changes: replace(destBranchBase.getParent(), destBranchBase, parent); destBranchBase.setParent(parent); if (parent.getLeft() == node) parent.setRight(destBranchBase); else if (parent.getRight() == node) parent.setLeft(destBranchBase); // Ensure BEAST knows to update affected likelihoods: node.makeDirty(Tree.IS_FILTHY); parent.makeDirty(Tree.IS_FILTHY); destBranchBase.makeDirty(Tree.IS_FILTHY); }
// identify nodes to be moved as part of a coordinated exchange move private boolean findMovedPairs( Node geneTreeNode, Map<Node, Node> movedNodes, Set<String> chosenDescendants, double lowerHeight, double upperHeight) { if (geneTreeNode.isLeaf()) { final String descendantName = geneTreeNode.getID(); // returns true if this leaf is a descendant of the chosen species return chosenDescendants.contains(descendantName); } final Node leftChild = geneTreeNode.getLeft(); final Node rightChild = geneTreeNode.getRight(); // left child descendants are exclusively descendants of the chosen species tree node final boolean leftExclusive = findMovedPairs(leftChild, movedNodes, chosenDescendants, lowerHeight, upperHeight); // right child descendants are exclusively descendants of the chosen species tree node final boolean rightExclusive = findMovedPairs(rightChild, movedNodes, chosenDescendants, lowerHeight, upperHeight); final double nodeHeight = geneTreeNode.getHeight(); if (nodeHeight >= lowerHeight && nodeHeight < upperHeight) { if (leftExclusive ^ rightExclusive) { if (leftExclusive) { // leave right child attached to original parent movedNodes.put(geneTreeNode, rightChild); } else { // leaf left child attached to original parent movedNodes.put(geneTreeNode, leftChild); } } } // returns true if all descendants of this gene tree node are also descendants of the chosen // species tree node return leftExclusive && rightExclusive; }
/** * Set up node's parent as the new root with a height of destTime, with oldRoot as node's new * sister. * * @param node * @param oldRoot * @param destTime */ public void connectBranchToRoot(Node node, Node oldRoot, double destTime) { // Check argument validity: if (node.isRoot() || !oldRoot.isRoot()) throw new IllegalArgumentException("Illegal argument " + "to connectBranchToRoot()."); // Obtain existing parent of node and set new time: Node newRoot = node.getParent(); newRoot.setHeight(destTime); // Implement topology changes: newRoot.setParent(null); if (newRoot.getLeft() == node) newRoot.setRight(oldRoot); else if (newRoot.getRight() == node) newRoot.setLeft(oldRoot); oldRoot.setParent(newRoot); // Ensure BEAST knows to recalculate affected likelihood: newRoot.makeDirty(Tree.IS_FILTHY); oldRoot.makeDirty(Tree.IS_FILTHY); node.makeDirty(Tree.IS_FILTHY); }
private int isg(final Node n) { return (n.getLeft().isLeaf() && n.getRight().isLeaf()) ? 0 : 1; }
/** Recalculates all the intervals for the given beast.tree. */ @SuppressWarnings("unchecked") protected void calculateIntervals() { Tree tree = treeInput.get(); final int nodeCount = tree.getNodeCount(); times = new double[nodeCount]; int[] childCounts = new int[nodeCount]; collectTimes(tree, times, childCounts); indices = new int[nodeCount]; HeapSort.sort(times, indices); if (intervals == null || intervals.length != nodeCount) { intervals = new double[nodeCount]; lineageCounts = new int[nodeCount]; lineagesAdded = new List[nodeCount]; lineagesRemoved = new List[nodeCount]; // lineages = new List[nodeCount]; storedIntervals = new double[nodeCount]; storedLineageCounts = new int[nodeCount]; } else { for (List<Node> l : lineagesAdded) { if (l != null) { l.clear(); } } for (List<Node> l : lineagesRemoved) { if (l != null) { l.clear(); } } } // start is the time of the first tip double start = times[indices[0]]; int numLines = 0; int nodeNo = 0; intervalCount = 0; while (nodeNo < nodeCount) { int lineagesRemoved = 0; int lineagesAdded = 0; double finish = times[indices[nodeNo]]; double next; do { final int childIndex = indices[nodeNo]; final int childCount = childCounts[childIndex]; // don't use nodeNo from here on in do loop nodeNo += 1; if (childCount == 0) { addLineage(intervalCount, tree.getNode(childIndex)); lineagesAdded += 1; } else { lineagesRemoved += (childCount - 1); // record removed lineages final Node parent = tree.getNode(childIndex); // assert childCounts[indices[nodeNo]] == beast.tree.getChildCount(parent); // for (int j = 0; j < lineagesRemoved + 1; j++) { for (int j = 0; j < childCount; j++) { Node child = j == 0 ? parent.getLeft() : parent.getRight(); removeLineage(intervalCount, child); } // record added lineages addLineage(intervalCount, parent); // no mix of removed lineages when 0 th if (multifurcationLimit == 0.0) { break; } } if (nodeNo < nodeCount) { next = times[indices[nodeNo]]; } else break; } while (Math.abs(next - finish) <= multifurcationLimit); if (lineagesAdded > 0) { if (intervalCount > 0 || ((finish - start) > multifurcationLimit)) { intervals[intervalCount] = finish - start; lineageCounts[intervalCount] = numLines; intervalCount += 1; } start = finish; } // add sample event numLines += lineagesAdded; if (lineagesRemoved > 0) { intervals[intervalCount] = finish - start; lineageCounts[intervalCount] = numLines; intervalCount += 1; start = finish; } // coalescent event numLines -= lineagesRemoved; } intervalsKnown = true; }