2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
5 // Copyright (C) 2008-2009 Christian M. Zmasek
6 // Copyright (C) 2008-2009 Burnham Institute for Medical Research
7 // Copyright (C) 2000-2001 Washington University School of Medicine
8 // and Howard Hughes Medical Institute
11 // This library is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU Lesser General Public
13 // License as published by the Free Software Foundation; either
14 // version 2.1 of the License, or (at your option) any later version.
16 // This library is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 // Lesser General Public License for more details.
21 // You should have received a copy of the GNU Lesser General Public
22 // License along with this library; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
25 // Contact: phylosoft @ gmail . com
26 // WWW: www.phylosoft.org/forester
28 package org.forester.sdi;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.List;
35 import org.forester.io.parsers.PhylogenyParser;
36 import org.forester.phylogeny.Phylogeny;
37 import org.forester.phylogeny.PhylogenyMethods;
38 import org.forester.phylogeny.PhylogenyNode;
39 import org.forester.phylogeny.factories.ParserBasedPhylogenyFactory;
40 import org.forester.phylogeny.factories.PhylogenyFactory;
41 import org.forester.phylogeny.iterators.PhylogenyNodeIterator;
42 import org.forester.util.ForesterUtil;
45 * Allows to <ul> <li> <li> <li> </ul>
51 * @author Christian M. Zmasek
53 * @version 1.400 -- last modified: 10/29/2005
55 public class ORcount {
57 private static final String[] group_1 = { "ANOGA", "DROME", "CAEBR", "CAEEL" };
58 private static final String[] group_2 = { "CIOIN", "FUGRU", "MOUSE", "RAT",
60 private static final String[] all_species = { "ANOGA", "DROME", "CAEBR", "CAEEL",
61 "CIOIN", "FUGRU", "MOUSE", "RAT", "HUMAN" };
62 private final Phylogeny[] _trees;
63 private HashMap<String, HashMap<Object, Integer>> _species = null;
64 private ArrayList<String> _names = null;
65 private int _group1_vs_2_counter = 0;
68 * Default contructor which
70 public ORcount( final Phylogeny[] trees ) {
72 } // ORcount( final Phylogeny[] trees )
74 private void count( final PhylogenyNode node ) {
75 final List<PhylogenyNode> external_nodes = node.getAllExternalDescendants();
76 for( int i = 1; i < external_nodes.size(); ++i ) {
77 for( int j = 0; j < i; ++j ) {
78 final PhylogenyNode node_i = external_nodes.get( i );
79 final PhylogenyNode node_j = external_nodes.get( j );
80 final String si = PhylogenyMethods.getSpecies( node_i );
81 final String sj = PhylogenyMethods.getSpecies( node_j );
82 count( si, sj, node_i.getName(), node_j.getName() );
85 } // count( PhylogenyNode )
87 private void count( final String a, final String b, final String seq_name_a, final String seq_name_b ) {
88 HashMap<Object, Integer> h1 = _species.get( a );
90 throw new RuntimeException( "Unexpected error: Species \"" + a + "\" not present in species matrix." );
92 Object h2 = h1.get( b );
93 String species_in_h1 = b;
94 // We only look at the half matrix, and we do not know/care about the
96 // of the keys (species).
98 h1 = _species.get( b );
100 throw new RuntimeException( "Unexpected error: Species \"" + b + "\" not present in species matrix." );
106 throw new RuntimeException( "Unexpected error: Species \"" + a + "\" not present in species matrix." );
108 h1.put( species_in_h1, new Integer( ( ( Integer ) h2 ).intValue() + 1 ) );
109 _names.add( a + "-" + seq_name_a + " = " + b + "-" + seq_name_b );
110 } // count( String, String )
112 public void countSharedAncestralClades( final Phylogeny tree,
113 final int bootstrap_threshold,
114 final String[] group_1,
115 final String[] group_2 ) {
116 if ( ( group_1 == null ) || ( group_2 == null ) ) {
117 throw new IllegalArgumentException( "String[](s) in arguments to method \"ORcount.countSharedAncestralClades\" is (are) null." );
119 if ( !tree.isRooted() ) {
120 throw new IllegalArgumentException( "Phylogeny must be rooted in order to count shared ancestral clades." );
122 final PhylogenyNodeIterator it = tree.iteratorPostorder();
123 tree.setIndicatorsToZero();
124 while ( it.hasNext() ) {
125 final PhylogenyNode current_node = it.next();
126 if ( current_node.getNumberOfDescendants() != 2 ) {
127 throw new IllegalArgumentException( "Phylogeny can not contain multifurcations in order to count shared ancestral clades." );
129 if ( !current_node.isExternal() ) {
130 final PhylogenyNode child1 = current_node.getChildNode1();
131 final PhylogenyNode child2 = current_node.getChildNode2();
132 if ( ( child1.getIndicator() == 1 ) || ( child2.getIndicator() == 1 ) ) {
133 current_node.setIndicator( ( byte ) 1 );
136 final List<PhylogenyNode> external_nodes = current_node.getAllExternalDescendants();
137 final String[] external_species = new String[ external_nodes.size() ];
138 for( int i = 0; i < external_nodes.size(); ++i ) {
139 final PhylogenyNode n = external_nodes.get( i );
140 external_species[ i ] = PhylogenyMethods.getSpecies( n ).trim().toUpperCase();
142 if ( ForesterUtil.isIntersecting( external_species, group_1 )
143 && ForesterUtil.isIntersecting( external_species, group_2 ) ) {
144 current_node.setIndicator( ( byte ) 1 );
145 if ( ( group_1.length == 1 ) && ( group_2.length == 1 ) ) {
146 count( group_1[ 0 ], group_2[ 0 ], "name a", "name b" );
149 increaseGroup1Vs2Counter();
155 } // countSharedAncestralClades( Phylogeny, int )
157 public void countSharedAncestralClades( final Phylogeny[] trees, final int bootstrap_threshold ) {
158 for( int i = 1; i < ORcount.all_species.length; ++i ) {
159 for( int j = 0; j < i; ++j ) {
160 final String all_i = ORcount.all_species[ i ].trim().toUpperCase();
161 final String all_j = ORcount.all_species[ j ].trim().toUpperCase();
162 final String[] a = { all_i };
163 final String[] b = { all_j };
164 for( int k = 0; k < trees.length; ++k ) {
165 countSharedAncestralClades( trees[ k ], bootstrap_threshold, a, b );
170 if ( ( ORcount.group_1 != null ) && ( ORcount.group_2 != null ) && ( ORcount.group_1.length > 0 )
171 && ( ORcount.group_2.length > 0 ) ) {
172 setGroup1Vs2Counter( 0 );
173 for( int k = 0; k < trees.length; ++k ) {
174 countSharedAncestralClades( trees[ k ], bootstrap_threshold, ORcount.group_1, ORcount.group_2 );
176 System.out.println( "\nCount [(" + ForesterUtil.stringArrayToString( ORcount.group_1 ) + ") vs ("
177 + ForesterUtil.stringArrayToString( ORcount.group_2 ) + ")] = " + getGroup1Vs2Counter() );
181 public void countSuperOrthologousRelations( final int bootstrap_threshold ) {
183 for( int i = 0; i < _trees.length; ++i ) {
184 countSuperOrthologousRelations( _trees[ i ], bootstrap_threshold );
188 private void countSuperOrthologousRelations( final Phylogeny tree, final int bootstrap_threshold ) {
189 final PhylogenyNodeIterator it = tree.iteratorPostorder();
190 if ( !tree.isRooted() ) {
191 throw new IllegalArgumentException( "Phylogeny must be rooted in order to count 1:1 orthologous relationships." );
193 // The purpose of this is to find all substrees
194 // which contain only speciation events on all their nodes.
195 // All nodes in these subtrees are "painted" with 0's, wheres
196 // the rest od the nodes in painted with 1's.
197 tree.setIndicatorsToZero();
199 while ( it.hasNext() ) {
200 final PhylogenyNode current_node = it.next();
201 if ( current_node.getNumberOfDescendants() != 2 ) {
202 throw new IllegalArgumentException( "Phylogeny can not contain multifurcations in order to count 1:1 orthologous relationships." );
204 if ( !current_node.isExternal() && !current_node.isHasAssignedEvent() ) {
205 throw new IllegalArgumentException( "All nodes must have duplication or speciation assigned in order to count 1:1 orthologous relationships." );
207 if ( !current_node.isExternal()
208 && ( current_node.isDuplication() || ( current_node.getChildNode1().getIndicator() == 1 ) || ( current_node
209 .getChildNode2().getIndicator() == 1 ) ) ) {
210 current_node.setIndicator( ( byte ) 1 );
213 // These find the largest subtrees containing only speciations
214 // and uses their largest nodes to count all possible species
216 // in their extant external nodes.
217 // ~~~ this could possibly be combined with the first iteration ~~
218 // <<<<<<<<<<<~~~~~~~~~~~~~~~<<<<<<<<<<<<<<<
220 while ( it.hasNext() ) {
221 final PhylogenyNode current_node = it.next();
222 if ( !current_node.isExternal()
223 && ( current_node.getIndicator() == 0 )
224 && ( current_node.isRoot() || ( current_node.getParent().getIndicator() == 1 ) )
225 && ( ( bootstrap_threshold < 1 ) || ( ( PhylogenyMethods.getConfidenceValue( current_node ) >= bootstrap_threshold )
226 && ( PhylogenyMethods.getConfidenceValue( current_node.getChildNode1() ) >= bootstrap_threshold ) && ( PhylogenyMethods
227 .getConfidenceValue( current_node.getChildNode2() ) >= bootstrap_threshold ) ) ) ) {
228 count( current_node );
231 } // countOneToOneOrthologs( Phylogeny, int )
233 // This puts all the species found in Phylogeny array _trees into
235 private void getAllSpecies() {
236 if ( ( getTrees() == null ) || ( getTrees().length < 1 ) ) {
237 throw new RuntimeException( "Phylogeny array in method \"getAllSpecies( HashMap hash )\" is null or empty." );
239 setSpecies( new HashMap<String, HashMap<Object, Integer>>() );
240 for( int i = 0; i < getTrees().length; ++i ) {
241 PhylogenyNode node = getTrees()[ i ].getFirstExternalNode();
242 while ( node != null ) {
243 getSpecies().put( PhylogenyMethods.getSpecies( node ), null );
244 node = node.getNextExternalNode();
247 } // void getAllSpecies( HashMap hash )
249 private int getGroup1Vs2Counter() {
250 return _group1_vs_2_counter;
253 private HashMap<String, HashMap<Object, Integer>> getSpecies() {
257 private Phylogeny[] getTrees() {
261 private void increaseGroup1Vs2Counter() {
262 _group1_vs_2_counter++;
265 private void printCount() {
266 if ( ( _species == null ) || ( _species.size() < 2 ) ) {
267 throw new RuntimeException( "Species HashMap in method \"setUpCountingMatrix()\" is null or contains less than two species." );
269 final Object[] species_array = _species.keySet().toArray();
270 final int s = species_array.length;
271 for( int i = 0; i < s - 1; ++i ) {
272 final String species = ( String ) species_array[ i ];
273 System.out.println();
274 System.out.println( species + ":" );
275 final HashMap<?, ?> h = _species.get( species );
276 // Setting up HashMaps linked to by hash (=_species)
277 // Diagonals are ignored, only half the matrix is needed.
278 for( int j = 1 + i; j < s; ++j ) {
279 final String sp = ( String ) species_array[ j ];
280 final int c = ( ( Integer ) h.get( sp ) ).intValue();
281 System.out.println( species + "-" + sp + ": " + c );
286 private void printNames() {
287 for( int i = 0; i < _names.size(); ++i ) {
288 System.out.println( i + ": " + _names.get( i ) );
292 public void reset() {
294 setUpCountingMatrix();
295 setGroup1Vs2Counter( 0 );
296 _names = new ArrayList<String>();
299 private void setGroup1Vs2Counter( final int group1_vs_2_counter ) {
300 _group1_vs_2_counter = group1_vs_2_counter;
303 private void setSpecies( final HashMap<String, HashMap<Object, Integer>> species ) {
307 private void setUpCountingMatrix() {
308 if ( ( getSpecies() == null ) || ( getSpecies().size() < 2 ) ) {
309 throw new RuntimeException( "Species HashMap in method \"setUpCountingMatrix()\" is null or contains less than two species." );
311 final Object[] species_array = getSpecies().keySet().toArray();
312 final int s = species_array.length;
313 for( int i = 0; i < s; ++i ) {
314 final String species = ( String ) species_array[ i ];
315 final HashMap<Object, Integer> h = new HashMap<Object, Integer>();
316 // Setting up HashMaps linked to by hash (=_species)
317 // Diagonals are ignored, only half the matrix is needed.
318 for( int j = 1 + i; j < s; ++j ) {
319 h.put( species_array[ j ], new Integer( 0 ) );
321 getSpecies().put( species, h );
325 private static void errorInCommandLine() {
326 System.out.println( "\nORcount: Error in command line.\n" );
327 System.out.println( "Usage: \"\"" );
328 System.out.println( "\nOptions:" );
329 System.out.println( " -" );
330 System.out.println( "" );
332 } // errorInCommandLine()
335 * Main method for this class.
337 * (Last modified: 11/26/03)
340 * gene tree file name (in NHX format with species names in
341 * species name fields and sequence names in sequence name
342 * fields; unless -n option is used)
344 public static void main( final String args[] ) {
345 if ( args.length == 0 ) {
346 ORcount.errorInCommandLine();
348 final Phylogeny[] trees = new Phylogeny[ args.length ];
349 final PhylogenyFactory factory = ParserBasedPhylogenyFactory.getInstance();
350 for( int i = 0; i < trees.length; ++i ) {
352 System.out.println( "Reading tree #" + i + " [" + args[ i ] + "]" );
353 final PhylogenyParser pp = ForesterUtil.createParserDependingOnFileType( new File( args[ i ] ), true );
354 trees[ i ] = factory.create( new File( args[ i ] ), pp )[ 0 ];
356 catch ( final Exception e ) {
357 System.out.println( "\nFailed to read \"" + args[ i ] + "\". Terminating.\n" );
361 System.out.println( "Finished reading in trees.\n\n" );
362 final ORcount or_count = new ORcount( trees );
364 System.out.println( "\n\n\n\"1:1 ORTHOLOGOUS GENE PAIRS\":\n" );
365 System.out.println( "\n\n\n\"SUPER ORTHOLOGOUS GENE PAIRS\":\n" );
366 or_count.countSuperOrthologousRelations( 0 );
367 or_count.printNames();
368 or_count.printCount();
369 // System.out.println( "\n\n\n\"SHARED ANCESTRAL CLADES\":\n");
371 // or_count.countSharedAncestralClades( trees, 0 );
373 catch ( final Exception e ) {
374 System.out.println( "\nException. Terminating.\n" );
375 System.out.println( "\nException is: " + e + "\n" );
379 System.out.println( "\nDone." );
382 } // End of class ORcount.