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