/*
* SplitUtils.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.evolution.tree;
import dr.evolution.util.TaxonList;
/**
* utilities for split systems
*
* @version $Id: SplitUtils.java,v 1.6 2005/05/24 20:25:57 rambaut Exp $
*
* @author Korbinian Strimmer
*/
public class SplitUtils
{
//
// Public stuff
//
/**
* creates a split system from a tree
* (using a pre-specified order of sequences)
*
* @param taxonList the list of taxa (order is important)
* @param tree
*/
public static SplitSystem getSplits(TaxonList taxonList, Tree tree)
{
int size = tree.getInternalNodeCount()-1;
SplitSystem splitSystem = new SplitSystem(taxonList, size);
boolean[][] splits = splitSystem.getSplitVector();
int j = 0;
for (int i = 0; i < tree.getInternalNodeCount(); i++) {
NodeRef node = tree.getInternalNode(i);
if (node != tree.getRoot()) {
getSplit(taxonList, tree, node, splits[j]);
j++;
}
}
return splitSystem;
}
/**
* creates a split system from a tree
* (using tree-induced order of sequences)
*
* @param tree
*/
public static SplitSystem getSplits(Tree tree)
{
return getSplits(tree, tree);
}
/**
* get split for branch associated with internal node
*
* @param taxonList
* @param tree
* @param internalNode Node
* @param split
*/
public static void getSplit(TaxonList taxonList, Tree tree, NodeRef internalNode, boolean[] split)
{
if (tree.isExternal(internalNode) || tree.isRoot(internalNode))
{
throw new IllegalArgumentException("Only internal nodes (and no root) nodes allowed");
}
// make sure split is reset
for (int i = 0; i < split.length; i++)
{
split[i] = false;
}
// mark all leafs downstream of the node
for (int i = 0; i < tree.getChildCount(internalNode); i++)
{
markNode(taxonList, tree, internalNode, split);
}
// standardize split (i.e. first index is alway true)
if ( !split[0] )
{
for (int i = 0; i < split.length; i++)
{
split[i] = !split[i];
}
}
}
/**
* checks whether two splits are identical
* (assuming they are of the same length
* and use the same leaf order)
*
* @param s1 split 1
* @param s2 split 2
*/
public static boolean isSame(boolean[] s1, boolean[] s2)
{
boolean reverse;
reverse = s1[0] != s2[0];
if (s1.length != s2.length)
throw new IllegalArgumentException("Splits must be of the same length!");
for (int i = 0; i < s1.length; i++)
{
if (reverse)
{
// splits not identical
if (s1[i] == s2[i]) return false;
}
else
{
// splits not identical
if (s1[i] != s2[i]) return false;
}
}
return true;
}
//
// Package stuff
//
static void markNode(TaxonList taxonList, Tree tree, NodeRef node, boolean[] split)
{
if (tree.isExternal(node))
{
String name = tree.getTaxonId(node.getNumber());
int index = taxonList.getTaxonIndex(name);
if (index < 0)
{
throw new IllegalArgumentException("INCOMPATIBLE IDENTIFIER (" + name + ")");
}
split[index] = true;
}
else
{
for (int i = 0; i < tree.getChildCount(node); i++)
{
markNode(taxonList, tree, tree.getChild(node, i), split);
}
}
}
}