@Test public void testOperator2() throws Exception { Tree tree; int taxaSize = 3; // make a caterpillar Node left = new ZeroBranchSANode(); left.setNr(0); left.setHeight(0.0); for (int i = 1; i < taxaSize; i++) { Node right = new ZeroBranchSANode(); right.setNr(i); right.setHeight(i); Node parent = new ZeroBranchSANode(); parent.setNr(taxaSize + i - 1); parent.setHeight(i); left.setParent(parent); parent.setLeft(left); right.setParent(parent); parent.setRight(right); left = parent; } left.setHeight(left.getRight().getHeight() + 2); tree = new Tree(left); System.out.println("Tree was = " + tree.getRoot().toShortNewick(false)); TreeDimensionJump operator = new TreeDimensionJump(); operator.initByName("tree", tree); double logHastingsRatio = operator.proposal(); System.out.println("Proposed tree = " + tree.getRoot().toShortNewick(false)); System.out.println("Log Hastings ratio = " + logHastingsRatio); }
// identify nodes that can serve as graft branches as part of a coordinated exchange move protected SetMultimap<Integer, Node> getGraftBranches(Node yNode) { final int yNumber = yNode.getNr(); final Set<String> cousinDescendants = findDescendants(yNode, yNumber); final SetMultimap<Integer, Node> allGraftBranches = HashMultimap.create(); final List<Tree> geneTrees = geneTreeInput.get(); for (int j = 0; j < nGeneTrees; j++) { final Tree geneTree = geneTrees.get(j); final Node geneTreeRootNode = geneTree.getRoot(); final Set<Node> jGraftBranches = new LinkedHashSet<>(); findGraftBranches(geneTreeRootNode, jGraftBranches, cousinDescendants); allGraftBranches.putAll(j, jGraftBranches); } return allGraftBranches; }
/** * 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; } }
@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); }
/** Ensure the class behaves properly, even when inputs are not specified. */ @Override public void initAndValidate() throws Exception { boolean sortNodesAlphabetically = false; if (dataInput.get() != null) { labels = dataInput.get().getTaxaNames(); } else if (m_taxonset.get() != null) { if (labels == null) { labels = m_taxonset.get().asStringList(); } else { // else labels were set by TreeParser c'tor sortNodesAlphabetically = true; } } else { if (isLabelledNewickInput.get()) { if (m_initial.get() != null) { labels = m_initial.get().getTaxonset().asStringList(); } else { labels = new ArrayList<>(); createUnrecognizedTaxa = true; sortNodesAlphabetically = true; } } else { if (m_initial.get() != null) { // try to pick up taxa from initial tree final Tree tree = m_initial.get(); if (tree.m_taxonset.get() != null) { labels = tree.m_taxonset.get().asStringList(); } else { // m_sLabels = null; } } else { // m_sLabels = null; } } // m_bIsLabelledNewick = false; } final String newick = newickInput.get(); if (newick == null || newick.equals("")) { // can happen while initalising Beauti final Node dummy = new Node(); setRoot(dummy); } else { try { setRoot(parseNewick(newickInput.get())); } catch (ParseCancellationException e) { throw new RuntimeException( "TreeParser cannot make sense of the Newick string " + "provided. It gives the following clue:\n" + e.getMessage()); } } super.initAndValidate(); if (sortNodesAlphabetically) { // correct for node ordering: ensure order is alphabetical for (int i = 0; i < getNodeCount() && i < labels.size(); i++) { m_nodes[i].setID(labels.get(i)); } Node[] nodes = new Node[labels.size()]; System.arraycopy(m_nodes, 0, nodes, 0, labels.size()); Arrays.sort(nodes, (o1, o2) -> o1.getID().compareTo(o2.getID())); for (int i = 0; i < labels.size(); i++) { m_nodes[i] = nodes[i]; nodes[i].setNr(i); } } if (m_initial.get() != null) processTraits(m_initial.get().m_traitList.get()); else processTraits(m_traitList.get()); if (timeTraitSet != null) { adjustTreeNodeHeights(root); } else if (adjustTipHeightsInput.get()) { double treeLength = TreeUtils.getTreeLength(this, getRoot()); double extraTreeLength = 0.0; double maxTipHeight = 0.0; // all nodes should be at zero height if no date-trait is available for (int i = 0; i < getLeafNodeCount(); i++) { double height = getNode(i).getHeight(); if (maxTipHeight < height) { maxTipHeight = height; } extraTreeLength += height; getNode(i).setHeight(0); } double scaleFactor = (treeLength + extraTreeLength) / treeLength; final double SCALE_FACTOR_THRESHOLD = 0.001; // if the change in total tree length is more than 0.1% then give the user a warning! if (scaleFactor > 1.0 + SCALE_FACTOR_THRESHOLD) { DecimalFormat format = new DecimalFormat("#.##"); Log.info.println( "WARNING: Adjust tip heights attribute set to 'true' in " + getClass().getSimpleName()); Log.info.println( " has resulted in significant (>" + format.format(SCALE_FACTOR_THRESHOLD * 100.0) + "%) change in tree length."); Log.info.println( " Use " + adjustTipHeightsInput.getName() + "='false' to override this default."); Log.info.printf(" original max tip age = %8.3f\n", maxTipHeight); Log.info.printf(" new max tip age = %8.3f\n", 0.0); Log.info.printf(" original tree length = %8.3f\n", treeLength); Log.info.printf(" new tree length = %8.3f\n", treeLength + extraTreeLength); Log.info.printf(" TL scale factor = %8.3f\n", scaleFactor); } } if (m_taxonset.get() == null && labels != null && isLabelledNewickInput.get()) { m_taxonset.setValue(new TaxonSet(Taxon.createTaxonList(labels)), this); } initStateNodes(); } // init
/** * override this for proposals, * * @return log of Hastings Ratio, or Double.NEGATIVE_INFINITY if proposal should not be accepted * */ @Override public double proposal() { testing = isTestInput.get(); speciesTreeNodes = speciesTree.getNodesAsArray(); nLeafNodes = speciesTree.getLeafNodeCount(); nInternalNodes = speciesTree.getInternalNodeCount(); nSpeciesNodes = speciesTree.getNodeCount(); boolean isNarrow = isNarrowInput.get(); double logHastingsRatio = 0.0; if (isNarrow) { // only proceed to rearrange gene trees if the species tree can be changed // doesn't execute if testing if (!testing && !pickNarrow()) return Double.NEGATIVE_INFINITY; int validGP = 0; for (int i = nLeafNodes; i < nSpeciesNodes; ++i) { validGP += isg(speciesTree.getNode(i)); } final int c2 = sisg(yNode) + sisg(cNode); fillNodes(); // fills in movedNodes and graftNodes pruneAndRegraft(yNode, cNode, bNode); final int validGPafter = validGP - c2 + sisg(yNode) + sisg(cNode); logHastingsRatio += Math.log(validGP) - Math.log(validGPafter); } else { // only proceed to rearrange gene trees if the species tree can be changed // doesn't execute if testing if (!testing && !pickWide()) return Double.NEGATIVE_INFINITY; fillNodes(); // fills in movedNodes and graftNodes pruneAndRegraft(yNode, cNode, bNode); } for (final Tree geneTree : geneTreeInput.get()) geneTree.startEditing(null); // hack to stop beast.core.State.Trie memory leak for (int i = 0; i < czBranchCount; i++) { final List<SortedMap<Node, Node>> perBranchMovedNodes = movedNodes.get(i); final SetMultimap<Integer, Node> perBranchGraftNodes = graftNodes.get(i); final double logForward = rearrangeGeneTrees(perBranchMovedNodes, perBranchGraftNodes, true); assert logForward != Double.NEGATIVE_INFINITY; if (logForward == Double.NEGATIVE_INFINITY) return Double.NEGATIVE_INFINITY; else logHastingsRatio += logForward; } // compute reverse move (Hastings ratio denominator) final Node bNodeTmp = bNode; final Node cNodeTmp = cNode; bNode = cNodeTmp; cNode = bNodeTmp; fillNodes(); // fills in movedNodes and graftNodes for reverse move for (int i = 0; i < czBranchCount; i++) { final List<SortedMap<Node, Node>> perBranchMovedNodes = movedNodes.get(i); final SetMultimap<Integer, Node> perBranchGraftNodes = graftNodes.get(i); final double logReverse = rearrangeGeneTrees(perBranchMovedNodes, perBranchGraftNodes, false); assert logReverse != Double.NEGATIVE_INFINITY; if (logReverse == Double.NEGATIVE_INFINITY) return Double.NEGATIVE_INFINITY; else logHastingsRatio -= logReverse; } return logHastingsRatio; }
/** 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; }