improving GSDI, under construction...
[jalview.git] / forester / java / src / org / forester / sdi / SDIse.java
1 // $Id:
2 // FORESTER -- software libraries and applications
3 // for evolutionary biology research and applications.
4 //
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
9 // All rights reserved
10 //
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.
15 //
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.
20 //
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
24 //
25 // Contact: phylosoft @ gmail . com
26 // WWW: www.phylosoft.org/forester
27
28 package org.forester.sdi;
29
30 import org.forester.phylogeny.Phylogeny;
31 import org.forester.phylogeny.PhylogenyNode;
32 import org.forester.phylogeny.data.Event;
33
34 /*
35  * Implements our algorithm for speciation - duplication inference (SDI). <p>
36  * Reference: </p> <ul> <li>Zmasek, C.M. and Eddy, S.R. (2001) "A simple
37  * algorithm to infer gene duplication and speciation events on a gene tree".
38  * Bioinformatics, in press. </ul> <p> The initialization is accomplished by:
39  * </p> <ul> <li>method "linkExtNodesOfG()" of class SDI: setting the links for
40  * the external nodes of the gene tree <li>"preorderReID(int)" from class
41  * Phylogeny: numbering of nodes of the species tree in preorder <li>the
42  * optional stripping of the species tree is accomplished by method
43  * "stripTree(Phylogeny,Phylogeny)" of class Phylogeny </ul> <p> The recursion
44  * part is accomplished by this class' method
45  * "geneTreePostOrderTraversal(PhylogenyNode)". <p> Requires JDK 1.2 or greater.
46  * 
47  * @see SDI#linkNodesOfG()
48  * 
49  * @see Phylogeny#preorderReID(int)
50  * 
51  * @see
52  * PhylogenyMethods#taxonomyBasedDeletionOfExternalNodes(Phylogeny,Phylogeny)
53  * 
54  * @see #geneTreePostOrderTraversal(PhylogenyNode)
55  * 
56  * @author Christian M. Zmasek
57  * 
58  * @version 1.102 -- last modified: 10/02/01
59  */
60 public class SDIse extends SDI {
61
62     /**
63      * Constructor which sets the gene tree and the species tree to be compared.
64      * species_tree is the species tree to which the gene tree gene_tree will be
65      * compared to - with method "infer(boolean)". Both Trees must be completely
66      * binary and rooted. The actual inference is accomplished with method
67      * "infer(boolean)". The mapping cost L can then be calculated with method
68      * "computeMappingCost()".
69      * <p>
70      * (Last modified: 01/11/01)
71      * 
72      * @see #infer(boolean)
73      * @see SDI#computeMappingCostL()
74      * @param gene_tree
75      *            reference to a rooted binary gene Phylogeny to which assign
76      *            duplication vs speciation, must have species names in the
77      *            species name fields for all external nodes
78      * @param species_tree
79      *            reference to a rooted binary species Phylogeny which might get
80      *            stripped in the process, must have species names in the
81      *            species name fields for all external nodes
82      * @throws SdiException 
83      */
84     public SDIse( final Phylogeny gene_tree, final Phylogeny species_tree ) throws SdiException {
85         super( gene_tree, species_tree );
86         _duplications_sum = 0;
87         getSpeciesTree().preOrderReId();
88         linkNodesOfG();
89         geneTreePostOrderTraversal( getGeneTree().getRoot() );
90     }
91
92     // Helper method for updateM( boolean, PhylogenyNode, PhylogenyNode )
93     // Calculates M for PhylogenyNode n, given that M for the two children
94     // of n has been calculated.
95     // (Last modified: 10/02/01)
96     private void calculateMforNode( final PhylogenyNode n ) {
97         if ( !n.isExternal() ) {
98             final boolean was_duplication = n.isDuplication();
99             PhylogenyNode a = n.getChildNode1().getLink(), b = n.getChildNode2().getLink();
100             while ( a != b ) {
101                 if ( a.getId() > b.getId() ) {
102                     a = a.getParent();
103                 }
104                 else {
105                     b = b.getParent();
106                 }
107             }
108             n.setLink( a );
109             Event event = null;
110             if ( ( a == n.getChildNode1().getLink() ) || ( a == n.getChildNode2().getLink() ) ) {
111                 event = Event.createSingleDuplicationEvent();
112                 if ( !was_duplication ) {
113                     ++_duplications_sum;
114                 }
115             }
116             else {
117                 event = Event.createSingleSpeciationEvent();
118                 if ( was_duplication ) {
119                     --_duplications_sum;
120                 }
121             }
122             n.getNodeData().setEvent( event );
123         }
124     } // calculateMforNode( PhylogenyNode )
125
126     /**
127      * Traverses the subtree of PhylogenyNode g in postorder, calculating the
128      * mapping function M, and determines which nodes represent speciation
129      * events and which ones duplication events.
130      * <p>
131      * Preconditions: Mapping M for external nodes must have been calculated and
132      * the species tree must be labelled in preorder.
133      * <p>
134      * (Last modified: 01/11/01)
135      * 
136      * @param g
137      *            starting node of a gene tree - normally the root
138      */
139     void geneTreePostOrderTraversal( final PhylogenyNode g ) {
140         PhylogenyNode a, b;
141         if ( !g.isExternal() ) {
142             geneTreePostOrderTraversal( g.getChildNode( 0 ) );
143             geneTreePostOrderTraversal( g.getChildNode( 1 ) );
144             a = g.getChildNode( 0 ).getLink();
145             b = g.getChildNode( 1 ).getLink();
146             while ( a != b ) {
147                 if ( a.getId() > b.getId() ) {
148                     a = a.getParent();
149                 }
150                 else {
151                     b = b.getParent();
152                 }
153             }
154             g.setLink( a );
155             // Determines whether dup. or spec.
156             Event event = null;
157             if ( ( a == g.getChildNode( 0 ).getLink() ) || ( a == g.getChildNode( 1 ).getLink() ) ) {
158                 event = Event.createSingleDuplicationEvent();
159                 ++_duplications_sum;
160             }
161             else {
162                 event = Event.createSingleSpeciationEvent();
163             }
164             g.getNodeData().setEvent( event );
165         }
166     } // geneTreePostOrderTraversal( PhylogenyNode )
167
168     /**
169      * Updates the mapping function M after the root of the gene tree has been
170      * moved by one branch. It calculates M for the root of the gene tree and
171      * one of its two children.
172      * <p>
173      * To be used ONLY by method "SDIunrooted.fastInfer(Phylogeny,Phylogeny)".
174      * <p>
175      * (Last modfied: 10/02/01)
176      * 
177      * @param prev_root_was_dup
178      *            true if the previous root was a duplication, false otherwise
179      * @param prev_root_c1
180      *            child 1 of the previous root
181      * @param prev_root_c2
182      *            child 2 of the previous root
183      * @return number of duplications which have been assigned in gene tree
184      */
185     int updateM( final boolean prev_root_was_dup, final PhylogenyNode prev_root_c1, final PhylogenyNode prev_root_c2 ) {
186         final PhylogenyNode root = getGeneTree().getRoot();
187         if ( ( root.getChildNode1() == prev_root_c1 ) || ( root.getChildNode2() == prev_root_c1 ) ) {
188             calculateMforNode( prev_root_c1 );
189         }
190         else {
191             calculateMforNode( prev_root_c2 );
192         }
193         Event event = null;
194         if ( prev_root_was_dup ) {
195             event = Event.createSingleDuplicationEvent();
196         }
197         else {
198             event = Event.createSingleSpeciationEvent();
199         }
200         root.getNodeData().setEvent( event );
201         calculateMforNode( root );
202         return getDuplicationsSum();
203     } // updateM( boolean, PhylogenyNode, PhylogenyNode )
204 } // End of class SDIse.