source: branches/ralph/src/main/java/de/ugoe/cs/autoquest/tasktrees/alignment/pal/tree/UPGMATree.java @ 1577

Last change on this file since 1577 was 1577, checked in by rkrimmel, 10 years ago

Finished UPGMA implementation

File size: 4.2 KB
Line 
1// UPGMATree.java
2//
3// (c) 1999-2001 PAL Development Core Team
4//
5// This package may be distributed under the
6// terms of the Lesser GNU General Public License (LGPL)
7
8// Known bugs and limitations:
9// - computational complexity O(numSeqs^3)
10//   (this could be brought down to O(numSeqs^2)
11//   but this needs more clever programming ...)
12
13
14package de.ugoe.cs.autoquest.tasktrees.alignment.pal.tree;
15
16import java.util.ArrayList;
17
18import de.ugoe.cs.autoquest.tasktrees.alignment.algorithms.NumberSequence;
19import de.ugoe.cs.autoquest.tasktrees.alignment.matrix.UPGMAMatrix;
20import de.ugoe.cs.autoquest.tasktrees.alignment.pal.misc.Identifier;
21
22
23/**
24 * constructs a UPGMA tree from pairwise distances
25 *
26 * @version $Id: UPGMATree.java,v 1.9 2001/07/13 14:39:13 korbinian Exp $
27 *
28 * @author Korbinian Strimmer
29 * @author Alexei Drummond
30 */
31public class UPGMATree extends SimpleTree
32{
33        //
34        // Public stuff
35        //     
36
37        /**
38         * constructor UPGMA tree
39         * @param numberseqs
40         *
41         * @param m distance matrix
42         */
43        public UPGMATree(ArrayList<NumberSequence> numberseqs, UPGMAMatrix m)
44        {
45                if (m.size() < 2)
46                {
47                        new IllegalArgumentException("LESS THAN 2 TAXA IN DISTANCE MATRIX");
48                }
49       
50                this.numberseqs = numberseqs;
51                init(m);
52
53                while (true)
54                {
55                        findNextPair();
56                        newBranchLengths();
57                       
58                        if (numClusters == 2)
59                        {
60                                break;
61                        }
62                       
63                        newCluster();
64                }
65               
66                finish();
67                createNodeList();
68        }
69
70
71        //
72        // Private stuff
73        //
74        private ArrayList<NumberSequence> numberseqs;
75        private int numClusters;
76        private int besti, abi;
77        private int bestj, abj;
78        private int[] alias;
79        private double[][] distance;
80
81        private double[] height;
82        private int[] oc;
83
84        private double getDist(int a, int b)
85        {
86                return distance[alias[a]][alias[b]];
87        }
88       
89        private void init(UPGMAMatrix m)
90        {
91                numClusters = m.size();
92
93                distance = new double[numClusters][numClusters];
94                for (int i = 0; i < numClusters; i++)
95                {
96                        for (int j = 0; j < numClusters; j++)
97                        {
98                                distance[i][j] = m.get(i,j);
99                        }
100                }
101
102                for (int i = 0; i < numClusters; i++)
103                {
104                        Node tmp = NodeFactory.createNode();
105                        tmp.setIdentifier(new Identifier(Integer.toString(i)));
106                        tmp.addSequence(numberseqs.get(i));
107                        getRoot().addChild(tmp);
108                }
109               
110                alias = new int[numClusters];
111                for (int i = 0; i < numClusters; i++)
112                {
113                        alias[i] = i;
114                }
115                               
116                height = new double[numClusters];
117                oc = new int[numClusters];
118                for (int i = 0; i < numClusters; i++)
119                {
120                        height[i] = 0.0;
121                        oc[i] = 1;
122                }
123        }
124
125        private void finish()
126        {
127                distance = null;               
128        }
129
130        private void findNextPair()
131        {
132                besti = 0;
133                bestj = 1;
134                double dmin = getDist(0, 1);
135                for (int i = 0; i < numClusters-1; i++)
136                {
137                        for (int j = i+1; j < numClusters; j++)
138                        {
139                                if (getDist(i, j) < dmin)
140                                {
141                                        dmin = getDist(i, j);
142                                        besti = i;
143                                        bestj = j;
144                                }
145                        }
146                }
147                abi = alias[besti];
148                abj = alias[bestj];
149                //System.out.println("Found best pair: " + abi + "/" +abj + " - "+ besti+ "/"+bestj +" with distance " + dmin);
150               
151        }
152
153        private void newBranchLengths()
154        {
155                double dij = getDist(besti, bestj);
156               
157                getRoot().getChild(besti).setBranchLength(dij/2.0-height[abi]);
158                getRoot().getChild(bestj).setBranchLength(dij/2.0-height[abj]);
159        }
160
161        private void newCluster()
162        {
163                // Update distances
164                for (int k = 0; k < numClusters; k++)
165                {
166                        if (k != besti && k != bestj)
167                        {
168                                int ak = alias[k];
169                                double updated = updatedDistance(besti,bestj,k);
170                                distance[ak][abi] = distance[abi][ak] = updated;
171                        }
172                }
173                distance[abi][abi] = 0.0;
174
175                // Update UPGMA variables
176                height[abi] = getDist(besti, bestj)/2.0;
177                oc[abi] += oc[abj];
178               
179                // Index besti now represent the new cluster
180                getRoot().joinChildren(besti, bestj);
181               
182                // Update alias
183                for (int i = bestj; i < numClusters-1; i++)
184                {
185                        alias[i] = alias[i+1];
186                }
187               
188                numClusters--;
189        }
190
191       
192        /**
193         * compute updated distance between the new cluster (i,j)
194         * to any other cluster k
195         */
196        private double updatedDistance(int i, int j, int k)
197        {
198                int ai = alias[i];
199                int aj = alias[j];
200               
201                double ocsum = (double) (oc[ai]+oc[aj]);
202                double idist = getDist(k,i);
203                double jdist = getDist(k,j);
204                //TODO: Dirty hack to deal with infinity, insert proper solution here
205                if(Double.isInfinite(idist)) {
206                        idist = 100;
207                }
208                if(Double.isInfinite(jdist)) {
209                        jdist = 100;
210                }
211               
212                return  (oc[ai]/ocsum)*idist+
213                        (oc[aj]/ocsum)*jdist;
214        }
215}
Note: See TracBrowser for help on using the repository browser.