X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=forester%2Fjava%2Fsrc%2Forg%2Fforester%2Fphylogeny%2FPhylogeny.java;h=723fab8a478ed57f68ffd1d968e14fceeeb921d9;hb=7e2a839d55608212fed645ce9ffe3a3f4952fb17;hp=b1677b1c513db326045aa9477c296d8b8ce5ccb5;hpb=e174d62534f7fc6f3de133d523a402a87735b27f;p=jalview.git diff --git a/forester/java/src/org/forester/phylogeny/Phylogeny.java b/forester/java/src/org/forester/phylogeny/Phylogeny.java index b1677b1..723fab8 100644 --- a/forester/java/src/org/forester/phylogeny/Phylogeny.java +++ b/forester/java/src/org/forester/phylogeny/Phylogeny.java @@ -23,7 +23,7 @@ // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA // // Contact: phylosoft @ gmail . com -// WWW: www.phylosoft.org/forester +// WWW: https://sites.google.com/site/cmzmasek/home/software/forester package org.forester.phylogeny; @@ -39,7 +39,7 @@ import java.util.NoSuchElementException; import java.util.Vector; import org.forester.io.writers.PhylogenyWriter; -import org.forester.phylogeny.PhylogenyNodeI.NH_CONVERSION_SUPPORT_VALUE_STYLE; +import org.forester.phylogeny.PhylogenyNode.NH_CONVERSION_SUPPORT_VALUE_STYLE; import org.forester.phylogeny.data.BranchData; import org.forester.phylogeny.data.Confidence; import org.forester.phylogeny.data.Identifier; @@ -68,7 +68,7 @@ public class Phylogeny { private Confidence _confidence; private Identifier _identifier; private boolean _rerootable; - private HashMap _idhash; + private HashMap _id_to_node_map; private List _external_nodes_set; private Collection _sequenceRelationQueries; private Collection _relevant_sequence_relation_types; @@ -144,6 +144,10 @@ public class Phylogeny { } } + public void clearHashIdToNodeMap() { + setIdToNodeMap( null ); + } + /** * Returns a deep copy of this Phylogeny. *

@@ -155,65 +159,65 @@ public class Phylogeny { } /** - * Returns a shallow copy of this Phylogeny. + * Returns a deep copy of this Phylogeny. *

* (The resulting Phylogeny has its references in the external nodes * corrected, if they are lacking/obsolete in this.) */ - public Phylogeny copyShallow() { - return copyShallow( _root ); - } - - public Phylogeny copyShallow( final PhylogenyNode source ) { + public Phylogeny copy( final PhylogenyNode source ) { final Phylogeny tree = new Phylogeny(); if ( isEmpty() ) { tree.init(); return tree; } tree._rooted = _rooted; - tree._name = _name; - tree._description = _description; - tree._type = _type; + tree._name = new String( _name ); + tree._description = new String( _description ); + tree._type = new String( _type ); tree._rerootable = _rerootable; - tree._distance_unit = _distance_unit; - tree._confidence = _confidence; - tree._identifier = _identifier; + tree._distance_unit = new String( _distance_unit ); + if ( _confidence != null ) { + tree._confidence = ( Confidence ) _confidence.copy(); + } + if ( _identifier != null ) { + tree._identifier = ( Identifier ) _identifier.copy(); + } tree.setAllowMultipleParents( isAllowMultipleParents() ); - tree._root = PhylogenyMethods.copySubTreeShallow( source ); + tree._root = PhylogenyMethods.copySubTree( source ); return tree; } /** - * Returns a deep copy of this Phylogeny. + * Returns a shallow copy of this Phylogeny. *

* (The resulting Phylogeny has its references in the external nodes * corrected, if they are lacking/obsolete in this.) */ - public Phylogeny copy( final PhylogenyNode source ) { + public Phylogeny copyShallow() { + return copyShallow( _root ); + } + + public Phylogeny copyShallow( final PhylogenyNode source ) { final Phylogeny tree = new Phylogeny(); if ( isEmpty() ) { tree.init(); return tree; } tree._rooted = _rooted; - tree._name = new String( _name ); - tree._description = new String( _description ); - tree._type = new String( _type ); + tree._name = _name; + tree._description = _description; + tree._type = _type; tree._rerootable = _rerootable; - tree._distance_unit = new String( _distance_unit ); - if ( _confidence != null ) { - tree._confidence = ( Confidence ) _confidence.copy(); - } - if ( _identifier != null ) { - tree._identifier = ( Identifier ) _identifier.copy(); - } + tree._distance_unit = _distance_unit; + tree._confidence = _confidence; + tree._identifier = _identifier; tree.setAllowMultipleParents( isAllowMultipleParents() ); - tree._root = PhylogenyMethods.copySubTree( source ); + tree._root = PhylogenyMethods.copySubTreeShallow( source ); return tree; } /** - * Need the delete and/or rehash _idhash (not done automatically + * Need to call clearHashIdToNodeMap() afterwards (not done automatically * to allow client multiple deletions in linear time). * Need to call 'recalculateNumberOfExternalDescendants(boolean)' after this * if tree is to be displayed. @@ -269,7 +273,6 @@ public class Phylogeny { } } remove_us.removeConnections(); - setIdHash( null ); externalNodesHaveChanged(); } @@ -376,13 +379,6 @@ public class Phylogeny { return _identifier; } - // --------------------------------------------------------- - // Modification of Phylogeny topology and Phylogeny appearance - // --------------------------------------------------------- - private HashMap getIdHash() { - return _idhash; - } - /** * Returns the name of this Phylogeny. */ @@ -392,29 +388,16 @@ public class Phylogeny { /** * Finds the PhylogenyNode of this Phylogeny which has a matching ID number. - * Takes O(n) time. After method hashIDs() has been called it runs in - * constant time. - * - * @param id - * ID number (int) of the PhylogenyNode to find * @return PhylogenyNode with matching ID, null if not found */ - public PhylogenyNode getNode( final int id ) throws NoSuchElementException { + public PhylogenyNode getNode( final long id ) throws NoSuchElementException { if ( isEmpty() ) { throw new NoSuchElementException( "attempt to get node in an empty phylogeny" ); } - if ( _idhash != null ) { - return _idhash.get( id ); + if ( ( getIdToNodeMap() == null ) || getIdToNodeMap().isEmpty() ) { + reHashIdToNodeMap(); } - else { - for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); ) { - final PhylogenyNode node = iter.next(); - if ( node.getId() == id ) { - return node; - } - } - } - return null; + return getIdToNodeMap().get( id ); } /** @@ -431,32 +414,27 @@ public class Phylogeny { } final List nodes = getNodes( name ); if ( ( nodes == null ) || ( nodes.size() < 1 ) ) { - throw new IllegalArgumentException( "node named [" + name + "] not found" ); + throw new IllegalArgumentException( "node named \"" + name + "\" not found" ); } if ( nodes.size() > 1 ) { - throw new IllegalArgumentException( "node named [" + name + "] not unique" ); + throw new IllegalArgumentException( "node named \"" + name + "\" not unique" ); } return nodes.get( 0 ); } /** - * Return Node by TaxonomyId Olivier CHABROL : - * olivier.chabrol@univ-provence.fr + * This is time-inefficient since it runs a iterator each time it is called. * - * @param taxonomyID - * search taxonomy identifier - * @param nodes - * sublist node to search - * @return List node with the same taxonomy identifier */ - private List getNodeByTaxonomyID( final String taxonomyID, final List nodes ) { - final List retour = new ArrayList(); - for( final PhylogenyNode node : nodes ) { - if ( taxonomyID.equals( PhylogenyMethods.getTaxonomyIdentifier( node ) ) ) { - retour.add( node ); - } + public int getNodeCount() { + if ( isEmpty() ) { + return 0; } - return retour; + int c = 0; + for( final PhylogenyNodeIterator it = iteratorPreorder(); it.hasNext(); it.next() ) { + ++c; + } + return c; } /** @@ -497,6 +475,20 @@ public class Phylogeny { return nodes; } + public List getNodesViaSequenceSymbol( final String seq_name ) { + if ( isEmpty() ) { + return null; + } + final List nodes = new ArrayList(); + for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); ) { + final PhylogenyNode n = iter.next(); + if ( n.getNodeData().isHasSequence() && n.getNodeData().getSequence().getSymbol().equals( seq_name ) ) { + nodes.add( n ); + } + } + return nodes; + } + public List getNodesViaTaxonomyCode( final String taxonomy_code ) { if ( isEmpty() ) { return null; @@ -564,28 +556,29 @@ public class Phylogeny { return nodes.get( 0 ); } - /** - * This is time-inefficient since it runs a iterator each time it is called. - * - */ - public int getNodeCount() { + public int getNumberOfBranches() { if ( isEmpty() ) { return 0; } int c = 0; - for( final PhylogenyNodeIterator it = iteratorPreorder(); it.hasNext(); it.next() ) { + for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); iter.next() ) { ++c; } + if ( !isRooted() ) { + --c; + } return c; } - public int getNumberOfBranches() { + public int getNumberOfInternalNodes() { if ( isEmpty() ) { return 0; } int c = 0; - for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); iter.next() ) { - ++c; + for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); ) { + if ( iter.next().isInternal() ) { + ++c; + } } if ( !isRooted() ) { --c; @@ -672,70 +665,11 @@ public class Phylogeny { return _sequenceRelationQueries; } - /** - * List all species contains in all leaf under a node Olivier CHABROL : - * olivier.chabrol@univ-provence.fr - * - * @param node - * PhylogenyNode whose sub node species are returned - * @return species contains in all leaf under the param node - */ - private List getSubNodeTaxonomy( final PhylogenyNode node ) { - final List taxonomyList = new ArrayList(); - final List childs = node.getAllExternalDescendants(); - String speciesId = null; - for( final PhylogenyNode phylogenyNode : childs ) { - // taxId = new Long(phylogenyNode.getTaxonomyID()); - speciesId = PhylogenyMethods.getTaxonomyIdentifier( phylogenyNode ); - if ( !taxonomyList.contains( speciesId ) ) { - taxonomyList.add( speciesId ); - } - } - return taxonomyList; - } - - /** - * Create a map [], the list contains the - * species contains in all leaf under phylogeny node Olivier CHABROL : - * olivier.chabrol@univ-provence.fr - * - * @param node - * the tree root node - * @param map - * map to fill - */ - private void getTaxonomyMap( final PhylogenyNode node, final Map> map ) { - // node is leaf - if ( node.isExternal() ) { - return; - } - map.put( node, getSubNodeTaxonomy( node ) ); - getTaxonomyMap( node.getChildNode1(), map ); - getTaxonomyMap( node.getChildNode2(), map ); - } - public String getType() { return _type; } /** - * Hashes the ID number of each PhylogenyNode of this Phylogeny to its - * corresponding PhylogenyNode, in order to make method getNode( id ) run in - * constant time. Important: The user is responsible for calling this method - * (again) after this Phylogeny has been changed/created/renumbered. - */ - public void hashIDs() { - if ( isEmpty() ) { - return; - } - setIdHash( new HashMap() ); - for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); ) { - final PhylogenyNode node = iter.next(); - getIdHash().put( node.getId(), node ); - } - } - - /** * Deletes this Phylogeny. */ public void init() { @@ -745,17 +679,13 @@ public class Phylogeny { _description = ""; _type = ""; _distance_unit = ""; - _idhash = null; + _id_to_node_map = null; _confidence = null; _identifier = null; _rerootable = true; setAllowMultipleParents( Phylogeny.ALLOW_MULTIPLE_PARENTS_DEFAULT ); } - private boolean isAllowMultipleParents() { - return _allow_multiple_parents; - } - /** * Returns whether this is a completely binary tree (i.e. all internal nodes * are bifurcations). @@ -775,31 +705,6 @@ public class Phylogeny { } /** - * Util method to check if all element of a list is contains in the - * rangeList. Olivier CHABROL : olivier.chabrol@univ-provence.fr - * - * @param list - * list to be check - * @param rangeList - * the range list to compare - * @return true if all param list element are contains in param - * rangeList, false otherwise. - */ - private boolean isContains( final List list, final List rangeList ) { - if ( list.size() > rangeList.size() ) { - return false; - } - String l = null; - for( final Iterator iterator = list.iterator(); iterator.hasNext(); ) { - l = iterator.next(); - if ( !rangeList.contains( l ) ) { - return false; - } - } - return true; - } - - /** * Checks whether a Phylogeny object is deleted (or empty). * * @return true if the tree is deleted (or empty), false otherwise @@ -849,8 +754,8 @@ public class Phylogeny { if ( isEmpty() ) { return; } - _idhash = null; - int max = 0; + _id_to_node_map = null; + long max = 0; for( final PhylogenyNodeIterator it = iteratorPreorder(); it.hasNext(); ) { final PhylogenyNode node = it.next(); if ( node.isRoot() ) { @@ -866,18 +771,6 @@ public class Phylogeny { PhylogenyNode.setNodeCount( max + 1 ); } - public void preOrderReId() { - if ( isEmpty() ) { - return; - } - setIdHash( null ); - int i = PhylogenyNode.getNodeCount(); - for( final PhylogenyNodeIterator it = iteratorPreorder(); it.hasNext(); ) { - it.next().setId( i++ ); - } - PhylogenyNode.setNodeCount( i ); - } - /** * Prints descriptions of all external Nodes of this Phylogeny to * System.out. @@ -932,40 +825,11 @@ public class Phylogeny { * @param id * ID (int) of PhylogenyNode of this Phylogeny */ - public void reRoot( final int id ) { + public void reRoot( final long id ) { reRoot( getNode( id ) ); } /** - * Places the root of this Phylogeny on Branch b. The new root is always - * placed on the middle of the branch b. - * - */ - public void reRoot( final PhylogenyBranch b ) { - final PhylogenyNode n1 = b.getFirstNode(); - final PhylogenyNode n2 = b.getSecondNode(); - if ( n1.isExternal() ) { - reRoot( n1 ); - } - else if ( n2.isExternal() ) { - reRoot( n2 ); - } - else if ( ( n2 == n1.getChildNode1() ) || ( n2 == n1.getChildNode2() ) ) { - reRoot( n2 ); - } - else if ( ( n1 == n2.getChildNode1() ) || ( n1 == n2.getChildNode2() ) ) { - reRoot( n1 ); - } - else if ( ( n1.getParent() != null ) && n1.getParent().isRoot() - && ( ( n1.getParent().getChildNode1() == n2 ) || ( n1.getParent().getChildNode2() == n2 ) ) ) { - reRoot( n1 ); - } - else { - throw new IllegalArgumentException( "reRoot( Branch b ): b is not a branch." ); - } - } - - /** * Places the root of this Phylogeny on the parent branch PhylogenyNode n. * The new root is always placed on the middle of the branch. *

@@ -1145,10 +1009,6 @@ public class Phylogeny { } } - private void setAllowMultipleParents( final boolean allow_multiple_parents ) { - _allow_multiple_parents = allow_multiple_parents; - } - public void setConfidence( final Confidence confidence ) { _confidence = confidence; } @@ -1165,8 +1025,8 @@ public class Phylogeny { _identifier = identifier; } - void setIdHash( final HashMap idhash ) { - _idhash = idhash; + public void setIdToNodeMap( final HashMap idhash ) { + _id_to_node_map = idhash; } /** @@ -1198,7 +1058,7 @@ public class Phylogeny { public void setRoot( final PhylogenyNode n ) { _root = n; - } // setRoot( PhylogenyNode ) + } /** * Sets whether this Phylogeny is rooted or not. @@ -1239,6 +1099,10 @@ public class Phylogeny { } } + public String toNexus() { + return toNexus( NH_CONVERSION_SUPPORT_VALUE_STYLE.NONE ); + } + public String toNexus( final NH_CONVERSION_SUPPORT_VALUE_STYLE svs ) { try { return new PhylogenyWriter().toNexus( this, svs ).toString(); @@ -1248,10 +1112,6 @@ public class Phylogeny { } } - public String toNexus() { - return toNexus( NH_CONVERSION_SUPPORT_VALUE_STYLE.NONE ); - } - public String toPhyloXML( final int phyloxml_level ) { try { return new PhylogenyWriter().toPhyloXML( this, phyloxml_level ).toString(); @@ -1292,4 +1152,120 @@ public class Phylogeny { setRooted( false ); return; } // unRoot() + + private HashMap getIdToNodeMap() { + return _id_to_node_map; + } + + /** + * Return Node by TaxonomyId Olivier CHABROL : + * olivier.chabrol@univ-provence.fr + * + * @param taxonomyID + * search taxonomy identifier + * @param nodes + * sublist node to search + * @return List node with the same taxonomy identifier + */ + private List getNodeByTaxonomyID( final String taxonomyID, final List nodes ) { + final List retour = new ArrayList(); + for( final PhylogenyNode node : nodes ) { + if ( taxonomyID.equals( PhylogenyMethods.getTaxonomyIdentifier( node ) ) ) { + retour.add( node ); + } + } + return retour; + } + + /** + * List all species contains in all leaf under a node Olivier CHABROL : + * olivier.chabrol@univ-provence.fr + * + * @param node + * PhylogenyNode whose sub node species are returned + * @return species contains in all leaf under the param node + */ + private List getSubNodeTaxonomy( final PhylogenyNode node ) { + final List taxonomyList = new ArrayList(); + final List childs = node.getAllExternalDescendants(); + String speciesId = null; + for( final PhylogenyNode phylogenyNode : childs ) { + // taxId = new Long(phylogenyNode.getTaxonomyID()); + speciesId = PhylogenyMethods.getTaxonomyIdentifier( phylogenyNode ); + if ( !taxonomyList.contains( speciesId ) ) { + taxonomyList.add( speciesId ); + } + } + return taxonomyList; + } + + /** + * Create a map [], the list contains the + * species contains in all leaf under phylogeny node Olivier CHABROL : + * olivier.chabrol@univ-provence.fr + * + * @param node + * the tree root node + * @param map + * map to fill + */ + private void getTaxonomyMap( final PhylogenyNode node, final Map> map ) { + // node is leaf + if ( node.isExternal() ) { + return; + } + map.put( node, getSubNodeTaxonomy( node ) ); + getTaxonomyMap( node.getChildNode1(), map ); + getTaxonomyMap( node.getChildNode2(), map ); + } + + private boolean isAllowMultipleParents() { + return _allow_multiple_parents; + } + + /** + * Util method to check if all element of a list is contains in the + * rangeList. Olivier CHABROL : olivier.chabrol@univ-provence.fr + * + * @param list + * list to be check + * @param rangeList + * the range list to compare + * @return true if all param list element are contains in param + * rangeList, false otherwise. + */ + private boolean isContains( final List list, final List rangeList ) { + if ( list.size() > rangeList.size() ) { + return false; + } + String l = null; + for( final Iterator iterator = list.iterator(); iterator.hasNext(); ) { + l = iterator.next(); + if ( !rangeList.contains( l ) ) { + return false; + } + } + return true; + } + + /** + * Hashes the ID number of each PhylogenyNode of this Phylogeny to its + * corresponding PhylogenyNode, in order to make method getNode( id ) run in + * constant time. Important: The user is responsible for calling this method + * (again) after this Phylogeny has been changed/created/renumbered. + */ + private void reHashIdToNodeMap() { + if ( isEmpty() ) { + return; + } + setIdToNodeMap( new HashMap() ); + for( final PhylogenyNodeIterator iter = iteratorPreorder(); iter.hasNext(); ) { + final PhylogenyNode node = iter.next(); + getIdToNodeMap().put( node.getId(), node ); + } + } + + private void setAllowMultipleParents( final boolean allow_multiple_parents ) { + _allow_multiple_parents = allow_multiple_parents; + } }