/* * AbstractCladeImportanceDistribution.java * * Copyright (c) 2002-2015 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.tree; import dr.evolution.tree.Clade; import dr.evolution.tree.ImportanceDistribution; import dr.evolution.tree.NodeRef; import dr.evolution.tree.Tree; import dr.inference.model.Likelihood; import java.util.BitSet; import java.util.HashMap; import java.util.List; /** * @author shhn001 */ public abstract class AbstractCladeImportanceDistribution implements ImportanceDistribution { /** * */ public AbstractCladeImportanceDistribution() { // TODO Auto-generated constructor stub } /** * creates a list with all clades but just the non-complementary ones. * ((A,B),(C,D)) just {A,B,C,D} and {A,B} are inserted. {A,B} is * complementary to {C,D} * * @param tree - the tree from which the clades are extracted * @param node - the starting node. All clades below starting at this branch * are added */ protected Clade getNonComplementaryClades(Tree tree, NodeRef node, List<Clade> parentClades, List<Clade> childClade, HashMap<String, Integer> taxonMap) { // create a new bit set for this clade BitSet bits = new BitSet(); Clade c = null; // check if the node is external if (tree.isExternal(node)) { // if so, the only taxon in the clade is I // int index = node.getNumber(); String taxon = tree.getTaxon(node.getNumber()).getId(); int index = taxonMap.get(taxon); bits.set(index); c = new Clade(bits, tree.getNodeHeight(node)); } else { // otherwise, call all children and add its taxon together to one // clade NodeRef childNode = tree.getChild(node, 0); // add just my first child to the list // the second child is complementary to the first Clade leftChild = getNonComplementaryClades(tree, childNode, parentClades, childClade, taxonMap); bits.or(leftChild.getBits()); childNode = tree.getChild(node, 1); // add just my first child to the list // the second child is complementary to the first Clade rightChild = getNonComplementaryClades(tree, childNode, parentClades, childClade, taxonMap); bits.or(rightChild.getBits()); c = new Clade(bits, tree.getNodeHeight(node)); if (leftChild.getSize() >= 2) { parentClades.add(c); childClade.add(leftChild); } else if (rightChild.getSize() >= 2) { parentClades.add(c); childClade.add(rightChild); } } return c; } /** * creates a list with all clades but just the non-complementary ones. * ((A,B),(C,D)) just {A,B,C,D} and {A,B} are inserted. {A,B} is * complementary to {C,D} * * @param tree - the tree from which the clades are extracted * @param node - the starting node. All clades below starting at this branch * are added */ protected Clade getNonComplementaryClades(Tree tree, NodeRef node, List<Clade> parentClades, List<Clade> childClade) { // create a new bit set for this clade BitSet bits = new BitSet(); Clade c = null; // check if the node is external if (tree.isExternal(node)) { // if so, the only taxon in the clade is I int index = node.getNumber(); bits.set(index); c = new Clade(bits, tree.getNodeHeight(node)); } else { // otherwise, call all children and add its taxon together to one // clade NodeRef childNode = tree.getChild(node, 0); // add just my first child to the list // the second child is complementary to the first Clade leftChild = getNonComplementaryClades(tree, childNode, parentClades, childClade); bits.or(leftChild.getBits()); childNode = tree.getChild(node, 1); // add just my first child to the list // the second child is complementary to the first Clade rightChild = getNonComplementaryClades(tree, childNode, parentClades, childClade); bits.or(rightChild.getBits()); c = new Clade(bits, tree.getNodeHeight(node)); if (leftChild.getSize() >= 2) { parentClades.add(c); childClade.add(leftChild); } else if (rightChild.getSize() >= 2) { parentClades.add(c); childClade.add(rightChild); } } return c; } /** * Creates a list with all clades of the tree * * @param tree - the tree from which the clades are extracted * @param node - the starting node. All clades below starting at this branch * are added */ protected Clade getClades(Tree tree, NodeRef node, List<Clade> parentClades, List<Clade> childClade) { // create a new bit set for this clade BitSet bits = new BitSet(); Clade c = null; // check if the node is external if (tree.isExternal(node)) { // if so, the only taxon in the clade is I int index = node.getNumber(); bits.set(index); c = new Clade(bits, tree.getNodeHeight(node)); } else { // otherwise, call all children and add its taxon together to one // clade NodeRef childNode = tree.getChild(node, 0); // add just my first child to the list // the second child is complementary to the first Clade leftChild = getClades(tree, childNode, parentClades, childClade); bits.or(leftChild.getBits()); childNode = tree.getChild(node, 1); // add just my first child to the list // the second child is complementary to the first Clade rightChild = getClades(tree, childNode, parentClades, childClade); bits.or(rightChild.getBits()); c = new Clade(bits, tree.getNodeHeight(node)); if (leftChild.getSize() >= 2) { parentClades.add(c); childClade.add(leftChild); } if (rightChild.getSize() >= 2) { parentClades.add(c); childClade.add(rightChild); } } return c; } /** * Creates a list with all clades of the tree * * @param taxonMap - the lookup map for the taxon representing an index * @param tree - the tree from which the clades are extracted * @param node - the starting node. All clades below starting at this branch * are added */ protected Clade getClades(Tree tree, NodeRef node, List<Clade> parentClades, List<Clade> childClade, HashMap<String, Integer> taxonMap) { // create a new bit set for this clade BitSet bits = new BitSet(); Clade c = null; // check if the node is external if (tree.isExternal(node)) { // if so, the only taxon in the clade is I // int index = node.getNumber(); String taxon = tree.getTaxon(node.getNumber()).getId(); int index = taxonMap.get(taxon); bits.set(index); c = new Clade(bits, tree.getNodeHeight(node)); } else { // otherwise, call all children and add its taxon together to one // clade NodeRef childNode = tree.getChild(node, 0); // add just my first child to the list // the second child is complementary to the first Clade leftChild = getClades(tree, childNode, parentClades, childClade, taxonMap); bits.or(leftChild.getBits()); childNode = tree.getChild(node, 1); // add just my first child to the list // the second child is complementary to the first Clade rightChild = getClades(tree, childNode, parentClades, childClade, taxonMap); bits.or(rightChild.getBits()); c = new Clade(bits, tree.getNodeHeight(node)); if (leftChild.getSize() >= 2) { parentClades.add(c); childClade.add(leftChild); } if (rightChild.getSize() >= 2) { parentClades.add(c); childClade.add(rightChild); } } return c; } /** * Creates a list with all clades of the tree * * @param tree - the tree from which the clades are extracted * @param node - the starting node. All clades below starting at this branch * are added * @param clades - the list in which the clades are stored * @param bits - a bit set to which the current bits of the clades are added */ public void getClades(Tree tree, NodeRef node, List<Clade> clades, BitSet bits) { // create a new bit set for this clade BitSet bits2 = new BitSet(); // check if the node is external if (tree.isExternal(node)) { // if so, the only taxon in the clade is I int index = node.getNumber(); bits2.set(index); } else { // otherwise, call all children and add its taxon together to one // clade for (int i = 0; i < tree.getChildCount(node); i++) { NodeRef child = tree.getChild(node, i); getClades(tree, child, clades, bits2); } // add my bit set to the list clades.add(new Clade(bits2, tree.getNodeHeight(node))); } // add my bit set to the bit set I was given // this is needed for adding all children clades together if (bits != null) { bits.or(bits2); } } /** * Creates a list with all clades of the tree * * @param tree - the tree from which the clades are extracted * @param node - the starting node. All clades heights below starting at this * branch are added * @param heights - the list in which the heights are stored */ public void getCladesHeights(Tree tree, NodeRef node, List<Double> heights) { // check if the node is external if (tree.isExternal(node)) { // if so, do nothing } else { // otherwise, call all children and add its taxon together to one // clade for (int i = 0; i < tree.getChildCount(node); i++) { NodeRef child = tree.getChild(node, i); getCladesHeights(tree, child, heights); } // add my bit set to the list heights.add(tree.getNodeHeight(node)); } } /** * Creates a list with all clades of the tree * * @param tree - the tree from which the clades are extracted * @param node - the starting node. All clades heights below starting at this * branch are added * @param heights - the list in which the heights are stored */ public void getRelativeCladesHeights(Tree tree, NodeRef node, List<Double> heights) { // check if the node is external if (tree.isExternal(node)) { // if so, do nothing } else { // otherwise, call all children and add its taxon together to one // clade for (int i = 0; i < tree.getChildCount(node); i++) { NodeRef child = tree.getChild(node, i); getRelativeCladesHeights(tree, child, heights); } // add my bit set to the list if (node != tree.getRoot()) { NodeRef parent = tree.getParent(node); heights.add(tree.getNodeHeight(node) / tree.getNodeHeight(parent)); } else { heights.add(1.0); } } } /** * Creates a list with all clades of the tree * * @param tree - the tree from which the clades are extracted * @param node - the starting node. All clades below starting at this branch * are added */ protected Clade getClade(Tree tree, NodeRef node) { // create a new bit set for this clade BitSet bits = new BitSet(); // check if the node is external if (tree.isExternal(node)) { // if so, the only taxon in the clade am I int index = node.getNumber(); bits.set(index); } else { // otherwise, call all children and add its taxon together to one // clade for (int i = 0; i < tree.getChildCount(node); i++) { NodeRef child = tree.getChild(node, i); Clade c = getClade(tree, child); bits.or(c.getBits()); } } Clade c = new Clade(bits, tree.getNodeHeight(node)); return c; } /** * Finds the parent of a given clade in a list of clades. The parent is the * direct parent and not the grandparent or so. * * @param clades - list of clades in which we are searching the parent * @param child - the child of whom we are searching the parent * @return the parent clade if found, otherwise itself */ protected Clade getParentClade(List<Clade> clades, Clade child) { Clade parent = null; BitSet childBits = child.getBits(); int parentSize = Integer.MAX_VALUE; // look in all clades of the list which contains the child and has the // minimum cardinality (least taxa) -> that's the parent :-) for (int i = 0; i < clades.size(); i++) { Clade tmp = clades.get(i); if (!child.equals(tmp) && containsClade(tmp.getBits(), childBits)) { if (parent == null || parentSize > tmp.getSize()) { parent = tmp; parentSize = parent.getSize(); } } } // if there isn't a parent, then you probably asked for the whole tree if (parent == null) { parent = child; } return parent; } /** * Checks if clade i contains clade j. * * @param i - the parent clade * @param j - the child clade * @return true, if i contains j */ protected boolean containsClade(Clade i, Clade j) { return containsClade(i.getBits(), j.getBits()); } /** * Checks if clade i contains clade j. * * @param i - the parent clade * @param j - the child clade * @return true, if i contains j */ protected boolean containsClade(BitSet i, BitSet j) { BitSet tmpI = (BitSet) i.clone(); // just set the bits which are either in j but not in i or in i but not // in j tmpI.xor(j); int numberOfBitsInEither = tmpI.cardinality(); // which bits are just in i tmpI.and(i); int numberIfBitJustInContaining = tmpI.cardinality(); // if the number of bits just in i is equal to the number of bits just // in one of i or j // then i contains j return numberOfBitsInEither == numberIfBitJustInContaining; } /* * (non-Javadoc) * * @see * dr.evolution.tree.ImportanceDistribution#addTree(dr.evolution.tree.Tree) */ public abstract void addTree(Tree tree); /* * (non-Javadoc) * * @see * dr.evolution.tree.ImportanceDistribution#getTreeProbability(dr.evolution * .tree.Tree) */ public abstract double getTreeProbability(Tree tree); /* * (non-Javadoc) * * @see * dr.evolution.tree.ImportanceDistribution#splitClade(dr.evolution.tree * .Clade, dr.evolution.tree.Clade[]) */ public abstract double splitClade(Clade parent, Clade[] children); public abstract double setNodeHeights(TreeModel tree, Likelihood likelihood); public abstract double getChanceForNodeHeights(TreeModel tree, Likelihood likelihood); }