/*
* PopTreeModel.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.oldevomodel.approxPopTree;
import dr.evolution.tree.FlexibleTree;
import dr.evolution.tree.NodeRef;
import dr.evolution.util.Taxon;
import dr.evomodel.tree.TreeModel;
import dr.xml.*;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
/**
* Package: PopTree
* Description:
* <p/>
* <p/>
* Created by
*
* @author Alexander V. Alekseyenko (alexander.alekseyenko@gmail.com)
* Date: Feb 1, 2010
* Time: 11:39:59 AM
*/
public class PopTreeModel extends FlexibleTree {
protected Map<NodeRef, LinkedList<NodeRef>> populations;
protected double time;
public PopTreeModel(TreeModel treeModel, double time) throws InvalidTreeException {
super(treeModel);
this.time = time;
this.populations = new HashMap<NodeRef, LinkedList<NodeRef>>();
enforcePopulations(time);
}
public void enforcePopulations(double time) {
enforcePopulations(time, this.getRoot());
}
public void enforcePopulations(double time, NodeRef node) {
beginTreeEdit();
reducePopulations(time, node);
endTreeEdit();
this.adoptTreeModelOrdering();
}
protected void reducePopulations(double time, NodeRef node) {
if (this.getNodeHeight(node) <= time) {
if (!this.isExternal(node))
this.setNodeHeight(node, time);
mergeSubtreePopulation(node);
} else {
for (int i = 0; i < this.getChildCount(node); ++i) {
NodeRef child = this.getChild(node, i);
reducePopulations(time, child);
}
}
}
public void splitPopulation(NodeRef node) {
splitPopulation(node, .5);
}
public void splitPopulation(NodeRef node, double frac) {
if (populations.containsKey(node) && populations.get(node).size() >= 1) {
//
}
}
public void mergePopulations(NodeRef parent) {
// assumes parent is an internal node which will become a new population node with all the crap below merged into this population
setNodeHeight(parent, time);
enforcePopulations(time, parent);
}
protected void mergeSubtreePopulation(NodeRef parent) {
/*
merge the subtree below node into a new population
*/
LinkedList<NodeRef> sequenceNodes;
sequenceNodes = new LinkedList<NodeRef>();
if (this.getNodeTaxon(parent) == null) {
this.setNodeTaxon(parent, new Taxon("popNode" + populations.size()));
}
if (this.isExternal(parent)) {
}
sequenceNodes.addFirst(parent); //push(parent);
while (true) {
NodeRef currentNode = sequenceNodes.removeFirst();
if (this.isExternal(currentNode)) {
sequenceNodes.addFirst(currentNode); //push(currentNode);
//this.setNodeAttribute(parent,"sequenceNodes",sequenceNodes);
populations.put(parent, sequenceNodes);
return;
}
int numChildren = this.getChildCount(currentNode);
for (int i = 0; getChildCount(currentNode) > 0;) {
NodeRef child = this.getChild(currentNode, i);
sequenceNodes.addFirst(child); //push(child);
this.removeChild(currentNode, child);
}
}
}
public int getPopulationNodeCount() {
return populations.size();
}
public String toString() {
return super.toString() + formatPopulationNodes();
}
public String formatPopulationNodes() {
String retval = "\n";
retval += getExternalNodeCount() + "\n";
for (NodeRef node : populations.keySet()) {
retval += this.getNodeTaxon(node).getId() + "(" + this.isExternal(node) + ")::";
for (NodeRef seqNode : populations.get(node)) {
retval += this.getNodeTaxon(seqNode).getId() + ",";
}
retval += "\n";
}
return retval;
}
public static XMLObjectParser PARSER = new AbstractXMLObjectParser() {
public Object parseXMLObject(XMLObject xo) throws XMLParseException {
TreeModel treeModel = (TreeModel) xo.getChild(TreeModel.class);
double timeCutoff = xo.getDoubleAttribute(POP_HEIGHT_CUTOFF);
PopTreeModel popTreeModel = null;
try {
popTreeModel = new PopTreeModel(treeModel, timeCutoff);
} catch (InvalidTreeException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
return popTreeModel;
}
public XMLSyntaxRule[] getSyntaxRules() {
return rules; //AUTOGENERATED METHOD IMPLEMENTATION
}
private final XMLSyntaxRule[] rules = {
new ElementRule(TreeModel.class),
AttributeRule.newDoubleRule(POP_HEIGHT_CUTOFF, false),
};
public String getParserDescription() {
return "Creates a Population Tree Model with specified divergence cut-off for population nodes";
}
public Class getReturnType() {
return PopTreeModel.class;
}
public String getParserName() {
return POP_TREE_MODEL;
}
};
public static final String POP_TREE_MODEL = "popTreeModel";
public static final String POP_HEIGHT_CUTOFF = "populationNodeHeight";
public static final String TREE_MODEL = "treeModel";
}