/* * SlidableTree.java * * Copyright (c) 2002-2017 Alexei Drummond, Andrew Rambaut and Marc Suchard * * This file is part of BEAST. * See the NOTICE file distributed with this work for additional * information regarding copyright ownership and licensing. * * BEAST is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * BEAST is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with BEAST; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301 USA */ package dr.evomodel.alloppnet.tree; import dr.evolution.tree.NodeRef; import dr.evolution.util.Taxon; import dr.math.MathUtils; /** * Interface for a binary tree which can support a Mau-et-al MCMC move * in which node heights `slide' and can change topology. * * @author Graham Jones * Date 2012-03-30 * */ /* The aim is to simplify code by not having to use a MutableTree with its long list of methods. The users of SlidableTree are 1. AlloppLeggedTree, for moves within tetraploid subtrees. 2. AlloppDiploidHistory. A SimpleTree is made for testing purposes. 3. PopsIOSpeciesTreeModel. Needs to be a Tree for logging. So I make and update a SimpleTree and delegate to that. 4. MulSpeciesTreeModel does not use it yet, but could do. Currently a MutableTree and uses near-copy of JH's code for MCMC moves. Same issue as PopsIOSpeciesTreeModel if use SlidableTree. It uses NodeRefs cause that's what SimpleTree uses. This means that clients have to implement get/setNumber when they have no use for node numbers. */ public interface SlidableTree { NodeRef getSlidableRoot(); int getSlidableNodeCount(); Taxon getSlidableNodeTaxon(NodeRef node); double getSlidableNodeHeight(NodeRef node); void setSlidableNodeHeight(NodeRef node, double height); boolean isExternalSlidable(NodeRef node); NodeRef getSlidableChild(NodeRef node, int i); void replaceSlidableChildren(NodeRef node, NodeRef lft, NodeRef rgt); void replaceSlidableRoot(NodeRef root); public class Utils { /* * This is an implementation of the ideas of * * Bayesian Phylogenetic Inference via Markov Chain Monte Carlo Methods * Bob Mau, Michael A. Newton, Bret Larget * Biometrics, Vol. 55, No. 1 (Mar., 1999), pp. 1-12 * * similar to implementation by Joseph Heled in TreeNodeSlide. * This version works on a SlidableTree rather than a SimpleTree and is * simpler than JH's version. It does not keep track of what was swapped. * Instead I assign popvalues to nodes via an ordering of species (see * fillinpopvals() in network). */ /* * For Mau-Newton-Larget MCMC moves on tree. * Do this, then change a node height, then call mnlReconstruct() * */ static public NodeRef[] mnlCanonical(SlidableTree tree) { final int count = tree.getSlidableNodeCount(); NodeRef[] order = new NodeRef[count]; mnlCanonicalSub(tree, tree.getSlidableRoot(), 0, order); return order; } /* * For Mau-etal MCMC moves on tree */ static public void mnlReconstruct(SlidableTree tree, NodeRef[] order) { final NodeRef root = mnlReconstructSub(tree, 0, (order.length - 1) / 2, order); tree.replaceSlidableRoot(root); } /* * ****************** private methods ********************** */ static private int mnlCanonicalSub(SlidableTree tree, NodeRef node, int nextloc, NodeRef[] order) { if( tree.isExternalSlidable(node) ) { order[nextloc] = node; assert (nextloc & 0x1) == 0; nextloc++; return nextloc; } final boolean swap = MathUtils.nextBoolean(); nextloc = mnlCanonicalSub(tree, tree.getSlidableChild(node, swap ? 1 : 0), nextloc, order); order[nextloc] = node; assert (nextloc & 0x1) == 1; nextloc++; nextloc = mnlCanonicalSub(tree, tree.getSlidableChild(node, swap ? 0 : 1), nextloc, order); return nextloc; } static private NodeRef mnlReconstructSub(SlidableTree tree, int from, int to, NodeRef[] order) { if (from == to) { return order[2*from]; } int rootIndex = highestNode(tree, order, from, to); NodeRef root = order[2 * rootIndex + 1]; NodeRef lft = mnlReconstructSub(tree, from, rootIndex, order); NodeRef rgt = mnlReconstructSub(tree, rootIndex+1, to, order); tree.replaceSlidableChildren(root, lft, rgt); return root; } static private int highestNode(SlidableTree tree, NodeRef[] order, int from, int to) { int rootIndex = -1; double maxh = -1.0; for (int i = from; i < to; ++i) { final double h = tree.getSlidableNodeHeight(order[2 * i + 1]); if (h > maxh) { maxh = h; rootIndex = i; } } return rootIndex; } } }