45096859f37ac9873dd56a806a1a2dc2cc5c99c1
[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      */
83     public SDIse( final Phylogeny gene_tree, final Phylogeny species_tree ) {
84         super( gene_tree, species_tree );
85         _duplications_sum = 0;
86         getSpeciesTree().preOrderReId();
87         linkNodesOfG();
88         geneTreePostOrderTraversal( getGeneTree().getRoot() );
89     }
90
91     // Helper method for updateM( boolean, PhylogenyNode, PhylogenyNode )
92     // Calculates M for PhylogenyNode n, given that M for the two children
93     // of n has been calculated.
94     // (Last modified: 10/02/01)
95     private void calculateMforNode( final PhylogenyNode n ) {
96         if ( !n.isExternal() ) {
97             final boolean was_duplication = n.isDuplication();
98             PhylogenyNode a = n.getChildNode1().getLink(), b = n.getChildNode2().getLink();
99             while ( a != b ) {
100                 if ( a.getId() > b.getId() ) {
101                     a = a.getParent();
102                 }
103                 else {
104                     b = b.getParent();
105                 }
106             }
107             n.setLink( a );
108             Event event = null;
109             if ( ( a == n.getChildNode1().getLink() ) || ( a == n.getChildNode2().getLink() ) ) {
110                 event = Event.createSingleDuplicationEvent();
111                 if ( !was_duplication ) {
112                     ++_duplications_sum;
113                 }
114             }
115             else {
116                 event = Event.createSingleSpeciationEvent();
117                 if ( was_duplication ) {
118                     --_duplications_sum;
119                 }
120             }
121             n.getNodeData().setEvent( event );
122         }
123     } // calculateMforNode( PhylogenyNode )
124
125     /**
126      * Traverses the subtree of PhylogenyNode g in postorder, calculating the
127      * mapping function M, and determines which nodes represent speciation
128      * events and which ones duplication events.
129      * <p>
130      * Preconditions: Mapping M for external nodes must have been calculated and
131      * the species tree must be labelled in preorder.
132      * <p>
133      * (Last modified: 01/11/01)
134      * 
135      * @param g
136      *            starting node of a gene tree - normally the root
137      */
138     void geneTreePostOrderTraversal( final PhylogenyNode g ) {
139         PhylogenyNode a, b;
140         if ( !g.isExternal() ) {
141             geneTreePostOrderTraversal( g.getChildNode( 0 ) );
142             geneTreePostOrderTraversal( g.getChildNode( 1 ) );
143             a = g.getChildNode( 0 ).getLink();
144             b = g.getChildNode( 1 ).getLink();
145             while ( a != b ) {
146                 if ( a.getId() > b.getId() ) {
147                     a = a.getParent();
148                 }
149                 else {
150                     b = b.getParent();
151                 }
152             }
153             g.setLink( a );
154             // Determines whether dup. or spec.
155             Event event = null;
156             if ( ( a == g.getChildNode( 0 ).getLink() ) || ( a == g.getChildNode( 1 ).getLink() ) ) {
157                 event = Event.createSingleDuplicationEvent();
158                 ++_duplications_sum;
159             }
160             else {
161                 event = Event.createSingleSpeciationEvent();
162             }
163             g.getNodeData().setEvent( event );
164         }
165     } // geneTreePostOrderTraversal( PhylogenyNode )
166
167     /**
168      * Updates the mapping function M after the root of the gene tree has been
169      * moved by one branch. It calculates M for the root of the gene tree and
170      * one of its two children.
171      * <p>
172      * To be used ONLY by method "SDIunrooted.fastInfer(Phylogeny,Phylogeny)".
173      * <p>
174      * (Last modfied: 10/02/01)
175      * 
176      * @param prev_root_was_dup
177      *            true if the previous root was a duplication, false otherwise
178      * @param prev_root_c1
179      *            child 1 of the previous root
180      * @param prev_root_c2
181      *            child 2 of the previous root
182      * @return number of duplications which have been assigned in gene tree
183      */
184     int updateM( final boolean prev_root_was_dup, final PhylogenyNode prev_root_c1, final PhylogenyNode prev_root_c2 ) {
185         final PhylogenyNode root = getGeneTree().getRoot();
186         if ( ( root.getChildNode1() == prev_root_c1 ) || ( root.getChildNode2() == prev_root_c1 ) ) {
187             calculateMforNode( prev_root_c1 );
188         }
189         else {
190             calculateMforNode( prev_root_c2 );
191         }
192         Event event = null;
193         if ( prev_root_was_dup ) {
194             event = Event.createSingleDuplicationEvent();
195         }
196         else {
197             event = Event.createSingleSpeciationEvent();
198         }
199         root.getNodeData().setEvent( event );
200         calculateMforNode( root );
201         return getDuplicationsSum();
202     } // updateM( boolean, PhylogenyNode, PhylogenyNode )
203 } // End of class SDIse.