/*
* ARGTree.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.arg;
import dr.evolution.tree.MutableTreeListener;
import dr.evolution.tree.NodeRef;
import dr.evolution.tree.Tree;
import dr.evolution.tree.TreeUtils;
import dr.evolution.util.MutableTaxonListListener;
import dr.evolution.util.Taxon;
import dr.evomodel.arg.ARGModel.Node;
import dr.util.Attributable;
import java.util.*;
public class ARGTree implements Tree {
//NodeRef root;
protected Taxon[] taxaList;
protected int taxaCount;
private final Node initialRoot;
public ARGModel argModel;
// private Map<NodeRef,Integer> mapARGNodesToInts;
private final Map<NodeRef,NodeRef> mapARGNodesToTreeNodes;
// public Map<NodeRef,Integer> getMappingInts() { return mapARGNodesToInts; }
// public Map<ARGModel.Node, NodeRef> getMappingNodes() { return mapARGNodesToTreeNodes; }
private int partition = -9;
// /**
// * Constructor to represent complete ARG as a tree
// *
// * @param arg
// */
// public ARGTree(ARGModel arg) {
// this.argModel = arg;
// mapNodesARGToTree = new HashMap<Node,Node>(arg.getNodeCount());
// root = arg.new Node((Node) arg.getRoot());
// }
// /**
// * Constructor for specific partition tree
// *
// * @param arg
// * @param partition
// */
// ArrayList<Node> nodeList;
public boolean wasRootTrimmed() {
return (root != initialRoot);
}
public String toGraphString() {
StringBuffer sb = new StringBuffer();
for (Node node : nodes) {
sb.append(node.number);
if (node.leftParent != null)
sb.append(" " + node.leftParent.number);
else
sb.append(" 0");
if (node.rightParent != null)
sb.append(" " + node.rightParent.number);
else
sb.append(" 0");
if (node.leftChild != null)
sb.append(" " + node.leftChild.number);
else
sb.append(" 0");
if (node.rightChild != null)
sb.append(" " + node.rightChild.number);
else
sb.append(" 0");
if (node.taxon != null)
sb.append(" " + node.taxon.toString());
sb.append("\n");
}
sb.append("Root = " + ((Node) getRoot()).number + "\n");
return new String(sb);
}
public ARGTree(ARGModel arg, int partition) {
this.argModel = arg;
mapARGNodesToTreeNodes = new HashMap<NodeRef,NodeRef>(arg.getNodeCount());
this.partition = partition;
ARGModel.Node node = arg.new Node(((Node) arg.getRoot()), partition);
initialRoot = node;
int j = arg.externalNodeCount;
node.stripOutDeadEnds();
root = node.stripOutSingleChildNodes(node);
node = root;
nodeCount = 2 * j - 1;
externalNodeCount = j;
internalNodeCount = j - 1;
nodes = new Node[nodeCount];
do {
node = (Node) TreeUtils.postorderSuccessor(this, node);
if (node.isExternal()) {
// keep same order as ARG, so do not need to reload tipStates/Partials
nodes[node.number] = node;
mapARGNodesToTreeNodes.put(node.mirrorNode,node);
} else {
// Reorder in new post-order succession
nodes[j] = node;
node.number = j;
j++;
mapARGNodesToTreeNodes.put(node.mirrorNode, node);
}
} while (node != root);
hasRates = false;
}
public Map<NodeRef,NodeRef> getMapping() {
return mapARGNodesToTreeNodes;
}
// public Map<NodeRef,Integer> getMapARGNodesToInts() {
// // Only need to map internal nodes
// Map<NodeRef,Integer> map = new HashMap<NodeRef,Integer>(getInternalNodeCount());
// for(int i=0; i<getInternalNodeCount(); i++) {
// ARGModel.Node node = (ARGModel.Node) getInternalNode(i);
// map.put(node.mirrorNode,node.number);
// }
// return map;
// }
public boolean checkForNullRights(Node node) {
return node.checkForNullRights();
}
// *****************************************************************
// Interface Tree
// *****************************************************************
/**
* Return the units that this tree is expressed in.
*/
public final Type getUnits() {
return units;
}
public void setUnits(Type units) {
this.units = units;
}
/**
* Sets the units that this tree is expressed in.
*/
/**
* @return a count of the number of nodes (internal + external) in this
* tree.
*/
public final int getNodeCount() {
return nodeCount;
}
public final boolean hasNodeHeights() {
return true;
}
public final double getNodeHeight(NodeRef node) {
//System.err.println(Tree.Utils.uniqueNewick(this, node));
//((Node)node))
return ((Node) node).getHeight();
}
public final double getNodeHeightUpper(NodeRef node) {
return ((Node) node).heightParameter.getBounds().getUpperLimit(0);
}
public final double getNodeHeightLower(NodeRef node) {
return ((Node) node).heightParameter.getBounds().getLowerLimit(0);
}
/**
* @param node
* @return the rate parameter associated with this node.
*/
public final double getNodeRate(NodeRef node) {
if (!hasRates) {
return 1.0;
}
return ((Node) node).getRate(partition);
}
public Object getNodeAttribute(NodeRef node, String name) {
throw new UnsupportedOperationException("TreeModel does not use NodeAttributes");
}
public Iterator getNodeAttributeNames(NodeRef node) {
throw new UnsupportedOperationException("TreeModel does not use NodeAttributes");
}
public double getNodeTrait(NodeRef node) {
if (!hasTraits) throw new IllegalArgumentException("Trait parameters have not been created");
return ((Node) node).getTrait();
}
public final Taxon getNodeTaxon(NodeRef node) {
return ((Node) node).taxon;
}
public final boolean isExternal(NodeRef node) {
return ((Node) node).isExternal();
}
public final boolean isRoot(NodeRef node) {
return (node == root);
}
public final int getChildCount(NodeRef node) {
//System.err.println("Cn for "+((Node)node).number);
return ((Node) node).getChildCount();
}
public final NodeRef getChild(NodeRef node, int i) {
return ((Node) node).getChild(i);
}
public final NodeRef getParent(NodeRef node) {
//System.err.println("Gimme!");
return ((Node) node).leftParent;
}
public final boolean hasBranchLengths() {
return true;
}
public final double getBranchLength(NodeRef node) {
NodeRef parent = getParent(node);
if (parent == null) {
return 0.0;
}
return getNodeHeight(parent) - getNodeHeight(node);
}
public final NodeRef getExternalNode(int i) {
return nodes[i];
}
public final NodeRef getInternalNode(int i) {
return nodes[i + externalNodeCount];
}
public final NodeRef getNode(int i) {
return nodes[i];
}
/**
* Returns the number of external nodes.
*/
public final int getExternalNodeCount() {
return externalNodeCount;
}
/**
* Returns the ith internal node.
*/
public final int getInternalNodeCount() {
return internalNodeCount;
}
/**
* Returns the root node of this tree.
*/
public final NodeRef getRoot() {
return root;
}
// **************************************************************
// TaxonList IMPLEMENTATION
// **************************************************************
/**
* @return a count of the number of taxa in the list.
*/
public int getTaxonCount() {
return getExternalNodeCount();
}
/**
* @return the ith taxon in the list.
*/
// public Taxon getTaxon(int taxonIndex) {
// return ((Node)getExternalNode(taxonIndex)).taxon;
// }
// public Taxon getTaxon(int taxonIndex) {
// if( taxonIndex >= taxaCount )
// return null;
// return taxaList[taxonIndex];
// }
public Taxon getTaxon(int taxonIndex) {
return ((Node) getExternalNode(taxonIndex)).taxon;
}
/**
* @return the ID of the taxon of the ith external node. If it doesn't have
* a taxon, returns the ID of the node itself.
*/
public String getTaxonId(int taxonIndex) {
Taxon taxon = getTaxon(taxonIndex);
if (taxon != null) {
return taxon.getId();
} else {
return null;
}
}
/**
* returns the index of the taxon with the given id.
*/
public int getTaxonIndex(String id) {
for (int i = 0, n = getTaxonCount(); i < n; i++) {
if (getTaxonId(i).equals(id)) return i;
}
return -1;
}
/**
* returns the index of the given taxon.
*/
public int getTaxonIndex(Taxon taxon) {
for (int i = 0, n = getTaxonCount(); i < n; i++) {
if (getTaxon(i) == taxon) return i;
}
return -1;
}
public List<Taxon> asList() {
List<Taxon> taxa = new ArrayList<Taxon>();
for (int i = 0, n = getTaxonCount(); i < n; i++) {
taxa.add(getTaxon(i));
}
return taxa;
}
public Iterator<Taxon> iterator() {
return new Iterator<Taxon>() {
private int index = -1;
public boolean hasNext() {
return index < getTaxonCount() - 1;
}
public Taxon next() {
index ++;
return getTaxon(index);
}
public void remove() { /* do nothing */ }
};
}
/**
* @param taxonIndex the index of the taxon whose attribute is being fetched.
* @param name the name of the attribute of interest.
* @return an object representing the named attributed for the taxon of the given
* external node. If the node doesn't have a taxon then the nodes own attribute
* is returned.
*/
public final Object getTaxonAttribute(int taxonIndex, String name) {
Taxon taxon = getTaxon(taxonIndex);
if (taxon != null) {
return taxon.getAttribute(name);
}
return null;
}
// **************************************************************
// MutableTaxonList IMPLEMENTATION
// **************************************************************
public int addTaxon(Taxon taxon) {
throw new IllegalArgumentException("Cannot add taxon to a TreeModel");
}
public boolean removeTaxon(Taxon taxon) {
throw new IllegalArgumentException("Cannot add taxon to a TreeModel");
}
public void setTaxonId(int taxonIndex, String id) {
throw new IllegalArgumentException("Cannot set taxon id in a TreeModel");
}
public void setTaxonAttribute(int taxonIndex, String name, Object value) {
throw new IllegalArgumentException("Cannot set taxon attribute in a TreeModel");
}
public void addMutableTreeListener(MutableTreeListener listener) {
} // Do nothing at the moment
public void addMutableTaxonListListener(MutableTaxonListListener listener) {
} // Do nothing at the moment
// **************************************************************
// Identifiable IMPLEMENTATION
// **************************************************************
protected String id = null;
/**
* @return the id.
*/
public String getId() {
return id;
}
/**
* Sets the id.
*/
public void setId(String id) {
this.id = id;
}
// **************************************************************
// Attributable IMPLEMENTATION
// **************************************************************
private Attributable.AttributeHelper treeAttributes = null;
/**
* Sets an named attribute for this object.
*
* @param name the name of the attribute.
* @param value the new value of the attribute.
*/
public void setAttribute(String name, Object value) {
if (treeAttributes == null)
treeAttributes = new Attributable.AttributeHelper();
treeAttributes.setAttribute(name, value);
}
/**
* @param name the name of the attribute of interest.
* @return an object representing the named attributed for this object.
*/
public Object getAttribute(String name) {
if (treeAttributes == null)
return null;
else
return treeAttributes.getAttribute(name);
}
/**
* @return an iterator of the attributes that this object has.
*/
public Iterator<String> getAttributeNames() {
if (treeAttributes == null)
return null;
else
return treeAttributes.getAttributeNames();
}
/**
* @return a string containing a newick representation of the tree
*/
public final String getNewick() {
return TreeUtils.newick(this);
}
public final String getUniqueNewick(){
return TreeUtils.uniqueNewick(this,this.getRoot());
}
/**
* @return a string containing a newick representation of the tree
*/
public String toString() {
return getNewick();
}
public Tree getCopy() {
throw new UnsupportedOperationException("please don't call this function");
}
// ***********************************************************************
// Private members
// ***********************************************************************
/**
* root node
*/
protected Node root = null;
protected int storedRootNumber;
/**
* list of internal nodes (including root)
*/
protected Node[] nodes = null;
protected Node[] storedNodes = null;
/**
* number of nodes (including root and tips)
*/
protected int nodeCount;
/**
* number of external nodes
*/
protected int externalNodeCount;
/**
* number of internal nodes (including root)
*/
protected int internalNodeCount;
/**
* holds the units of the trees branches.
*/
// private int units = SUBSTITUTIONS;
private Type units;
protected boolean inEdit = false;
private final boolean hasRates;
private final boolean hasTraits = false;
}