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; }
/** * 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 double rearrangeGeneTrees( List<SortedMap<Node, Node>> branchMovedNodes, SetMultimap<Integer, Node> branchGraftNodes, boolean forwardMove) { double logHastingsRatio = 0.0; for (int j = 0; j < nGeneTrees; j++) { final Set<Node> jForwardGraftNodes = branchGraftNodes.get(j); final SortedMap<Node, Node> jForwardMovedNodes = branchMovedNodes.get(j); for (final Entry<Node, Node> nodePair : jForwardMovedNodes.entrySet()) { final Node movedNode = nodePair.getKey(); final Node disownedChild = nodePair.getValue(); final double movedNodeHeight = movedNode.getHeight(); final List<Node> validGraftBranches = new ArrayList<>(); int forwardGraftCount = 0; for (Node potentialGraft : jForwardGraftNodes) { final double potentialGraftBottom = potentialGraft.getHeight(); double potentialGraftTop; if (potentialGraft.isRoot()) { potentialGraftTop = Double.POSITIVE_INFINITY; } else { potentialGraftTop = potentialGraft.getParent().getHeight(); } if (movedNodeHeight > potentialGraftBottom && movedNodeHeight < potentialGraftTop) { forwardGraftCount++; validGraftBranches.add(potentialGraft); } } // no compatible branches to graft this node on to // this only occurs when there is missing data and the gene tree root is in the "parent" // branch // or if two gene tree nodes which need moving are of equal height if (forwardGraftCount == 0) { return Double.NEGATIVE_INFINITY; } else { logHastingsRatio += Math.log(forwardGraftCount); if (forwardMove) { // only actually change gene trees if this is the forward move final Node chosenGraft = validGraftBranches.get(Randomizer.nextInt(forwardGraftCount)); pruneAndRegraft(movedNode, chosenGraft, disownedChild); } } } } return logHastingsRatio; }
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; }
/** * extract coalescent times and tip information into array times from beast.tree. * * @param tree the beast.tree * @param times the times of the nodes in the beast.tree * @param childCounts the number of children of each node */ protected static void collectTimes(Tree tree, double[] times, int[] childCounts) { Node[] nodes = tree.getNodesAsArray(); for (int i = 0; i < nodes.length; i++) { Node node = nodes[i]; times[i] = node.getHeight(); childCounts[i] = node.isLeaf() ? 0 : 2; } }
// fills forward nodes by destination branch (c through z) private void fillNodes() { // must be done before any changes are made to the gene or species trees Node childNode = cNode; movedNodes = new ArrayList<>(); graftNodes = new ArrayList<>(); czBranchCount = 0; while (childNode != zNode) { czBranchCount++; final Node parentNode = childNode.getParent(); final double childNodeHeight = childNode.getHeight(); final double parentNodeHeight = parentNode.getHeight(); final List<SortedMap<Node, Node>> perBranchMovedNodes = getMovedPairs(childNodeHeight, parentNodeHeight); final SetMultimap<Integer, Node> perBranchGraftNodes = getGraftBranches(childNode); movedNodes.add(0, perBranchMovedNodes); // needs to be added in reverse order graftNodes.add(0, perBranchGraftNodes); // because nodes must be grafted oldest to youngest childNode = parentNode; } }
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; } } }
@Override public double proposal() { Tree tree = treeInput.get(this); // randomly select leaf node int i = Randomizer.nextInt(taxonIndices.length); Node node = tree.getNode(taxonIndices[i]); double upper = node.getParent().getHeight(); // double lower = 0.0; // final double newValue = (Randomizer.nextDouble() * (upper -lower)) + lower; // scale node double scale = (scaleFactor + (Randomizer.nextDouble() * ((1.0 / scaleFactor) - scaleFactor))); final double newValue = node.getHeight() * scale; // check the tree does not get negative branch lengths if (newValue > upper) { return Double.NEGATIVE_INFINITY; } node.setHeight(newValue); return -Math.log(scale); }
// 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; }