]> git.donarmstrong.com Git - ape.git/blob - R/root.R
d02044fa627360bafaedf5055e8bfe3dce3d7d8c
[ape.git] / R / root.R
1 ## root.R (2009-11-15)
2
3 ##   Root of Phylogenetic Trees
4
5 ## Copyright 2004-2009 Emmanuel Paradis
6
7 ## This file is part of the R-package `ape'.
8 ## See the file ../COPYING for licensing issues.
9
10 is.rooted <- function(phy)
11 {
12     if (!inherits(phy, "phylo"))
13       stop('object "phy" is not of class "phylo"')
14     if (!is.null(phy$root.edge)) TRUE
15     else
16       if (tabulate(phy$edge[, 1])[length(phy$tip.label) + 1] > 2)
17         FALSE else TRUE
18 }
19
20 unroot <- function(phy)
21 {
22     if (!inherits(phy, "phylo"))
23       stop('object "phy" is not of class "phylo"')
24     if (dim(phy$edge)[1] < 3)
25       stop("cannot unroot a tree with two edges.")
26     ## delete FIRST the root.edge (in case this is sufficient to
27     ## unroot the tree, i.e. there is a multichotomy at the root)
28     if (!is.null(phy$root.edge)) phy$root.edge <- NULL
29     if (!is.rooted(phy)) return(phy)
30     ## We remove one of the edges coming from the root, and
31     ## eventually adding the branch length to the other one
32     ## also coming from the root.
33     ## In all cases, the node deleted is the 2nd one (numbered
34     ## nb.tip+2 in `edge'), so we simply need to renumber the
35     ## nodes by adding 1, except the root (this remains the
36     ## origin of the tree).
37     nb.tip <- length(phy$tip.label)
38     ROOT <- nb.tip + 1L
39     EDGEROOT <- which(phy$edge[, 1] == ROOT)
40     ## j: the target where to stick the edge
41     ## i: the edge to delete
42     if (phy$edge[EDGEROOT[1], 2] == ROOT + 1L) {
43         j <- EDGEROOT[2]
44         i <- EDGEROOT[1]
45     } else {
46         j <- EDGEROOT[1]
47         i <- EDGEROOT[2]
48     }
49     ## This should work whether the tree is in pruningwise or
50     ## cladewise order.
51     phy$edge <- phy$edge[-i, ]
52     nodes <- phy$edge > ROOT # renumber all nodes except the root
53     phy$edge[nodes] <- phy$edge[nodes] - 1L
54     if (!is.null(phy$edge.length)) {
55         phy$edge.length[j] <- phy$edge.length[j] + phy$edge.length[i]
56         phy$edge.length <- phy$edge.length[-i]
57     }
58     phy$Nnode <- phy$Nnode - 1L
59     if (!is.null(phy$node.label))
60       phy$node.label <- phy$node.label[-2]
61     phy
62 }
63
64 root <- function(phy, outgroup, node = NULL, resolve.root = FALSE)
65 {
66     if (!inherits(phy, "phylo"))
67       stop('object "phy" is not of class "phylo"')
68     phy <- reorder(phy)
69     n <- length(phy$tip.label)
70     ROOT <- n + 1
71     if (!is.null(node)) {
72         if (node <= n)
73             stop("incorrect node#: should be greater than the number of taxa")
74         outgroup <- NULL
75         newroot <- node
76     } else {
77         if (is.numeric(outgroup)) {
78             if (any(outgroup > n))
79                 stop("incorrect taxa#: should not be greater than the number of taxa")
80             outgroup <- sort(outgroup) # used below
81         }
82         if (is.character(outgroup))
83             outgroup <- which(phy$tip.label %in% outgroup)
84         if (length(outgroup) == n) return(phy)
85
86         ## First check that the outgroup is monophyletic--
87         ## unless there's only one tip specified of course
88         if (length(outgroup) > 1) {
89             seq.nod <- .Call("seq_root2tip", phy$edge, n,
90                              phy$Nnode, PACKAGE = "ape")
91             sn <- seq.nod[outgroup]
92             ## We go from the root to the tips: the sequence of nodes
93             ## is identical until the MRCA:
94             newroot <- ROOT
95             i <- 2 # we start at the 2nd position since the root
96                    # of the tree is a common ancestor to all tips
97             repeat {
98                 x <- unique(unlist(lapply(sn, "[", i)))
99                 if (length(x) != 1) break
100                 newroot <- x
101                 i <- i + 1
102             }
103             ## Check that all descendants of this node
104             ## are included in the outgroup.
105             ## (below is slightly faster than calling "bipartition")
106             desc <- which(unlist(lapply(seq.nod,
107                                         function(x) any(x %in% newroot))))
108             msg <- "the specified outgroup is not monophyletic"
109             ingroup <- (1:n)[-outgroup]
110             ## 'outgroup' and 'desc' are already sorted:
111             if (newroot != ROOT) {
112                 if (!identical(outgroup, desc) && !identical(ingroup, desc))
113                     stop(msg)
114             } else { # otherwise check monophyly of the ingroup
115                 if (!is.monophyletic(phy, ingroup)) stop(msg)
116             }
117         } else newroot <- phy$edge[which(phy$edge[, 2] == outgroup), 1]
118     }
119     N <- Nedge(phy)
120     oldNnode <- phy$Nnode
121     if (newroot == ROOT) {
122         if (resolve.root) {
123             snw <- which(phy$edge[, 1] == newroot)
124             if (length(snw) > 2) {
125                 a <- snw[1]:(snw[2] - 1)
126                 b <- snw[2]:N
127                 newnod <- oldNnode + n + 1
128                 phy$edge[snw[-1], 1] <- newnod
129                 phy$edge <- rbind(phy$edge[a, ], c(ROOT, newnod),
130                                   phy$edge[b, ])
131                 if (!is.null(phy$edge.length))
132                 phy$edge.length <-
133                     c(phy$edge.length[a], 0, phy$edge.length[b])
134                 phy$Nnode <- phy$Nnode + 1L
135                 ## node renumbering (see comments below)
136                 newNb <- integer(n + oldNnode)
137                 newNb[newroot] <- n + 1L
138                 sndcol <- phy$edge[, 2] > n
139                 phy$edge[sndcol, 2] <- newNb[phy$edge[sndcol, 2]] <-
140                     (n + 2):(n + phy$Nnode)
141                 phy$edge[, 1] <- newNb[phy$edge[, 1]]
142             }
143         }
144         return(phy)
145     }
146
147     phy$root.edge <- NULL # just in case...
148     Nclade <- tabulate(phy$edge[, 1])[ROOT] # degree of the root node
149     ## if only 2 edges connect to the root, we have to fuse them:
150     fuseRoot <- Nclade == 2
151
152     start <- which(phy$edge[, 1] == ROOT)
153     end <- c(start[-1] - 1, N)
154     o <- integer(N)
155     INV <- logical(N)
156
157     w <- which(phy$edge[, 2] == newroot)
158     nod <- phy$edge[w, 1]
159     i <- w
160     NEXT <- 1L
161
162     ## The loop below starts from the new root and goes up in the edge
163     ## matrix reversing the edges that need to be as well as well
164     ## inverting their order. The other edges must not be changed, so
165     ## their indices are stored in `stack'.
166     ## We then bind the other edges in a straightforward way.
167
168     if (nod != ROOT) {
169         ## it is important that the 3 next lines
170         ## are inside this "if" statement
171         o[NEXT] <- w
172         NEXT <- NEXT + 1L
173         INV[w] <- TRUE
174         i <- w - 1L
175         stack <- 0L
176         repeat {
177             if (phy$edge[i, 2] == nod) {
178                 if (stack) {
179                     o[NEXT:(NEXT + stack - 1L)] <- (i + 1L):(i + stack)
180                     NEXT <- NEXT + stack
181                     stack <- 0L
182                 }
183                 if (phy$edge[i, 1] == ROOT) break
184                 o[NEXT] <- i
185                 NEXT <- NEXT + 1L
186                 INV[i] <- TRUE
187                 nod <- phy$edge[i, 1]
188             } else stack <- stack + 1L
189             i <- i - 1L
190         }
191     }
192
193     ## we keep the edge leading to the old root if needed:
194     if (!fuseRoot) {
195         o[NEXT] <- i
196         INV[i] <- TRUE
197         NEXT <- NEXT + 1L
198     }
199
200     endOfOutgroup <- which(phy$edge[(w+1):N, 1] < newroot)[1] + w - 1
201     if (is.na(endOfOutgroup)) endOfOutgroup <- N
202     endOfClade <- end[end >= endOfOutgroup][1]
203
204     ## bind the other clades...
205     for (j in 1:Nclade) {
206         if (end[j] == endOfClade) next
207         ## do we have to fuse the two basal edges?
208         if (fuseRoot) {
209             phy$edge[start[j], 1] <- phy$edge[i, 2]
210             if (!is.null(phy$edge.length))
211                 phy$edge.length[start[j]] <- phy$edge.length[start[j]] +
212                     phy$edge.length[i]
213         } #else {
214           #  o[NEXT] <- i#start[j]
215           #  NEXT <- NEXT + 1L
216         #}
217         s <- start[j]:end[j]
218         ne <- length(s)
219         o[NEXT:(NEXT + ne - 1L)] <- s
220         NEXT <- NEXT + ne
221     }
222
223     ## possibly bind the edges below the outgroup till the end of the clade
224     if (all(endOfOutgroup != end)) {
225         j <- (endOfOutgroup + 1L):endOfClade
226         ## we must take care that the branch inversions done above
227         ## may have changed the hierarchy of clades here, so we
228         ## travel from the bottom of this series of edges
229         stack <- 0L
230         inverted <- phy$edge[INV, 1] # <- fails if ', 2]' is used
231         for (k in rev(j)) {
232             if (any(phy$edge[k, 1] == inverted)) {
233                 o[NEXT] <- k
234                 NEXT <- NEXT + 1L
235                 if (stack){
236                     o[NEXT:(NEXT + stack - 1L)] <- (k + 1L):(k + stack)
237                     NEXT <- NEXT + stack
238                     stack <- 0L
239                 }
240             } else stack <- stack + 1L
241         }
242     }
243
244     ## ... and the outgroup
245     s <- (w + 1L):endOfOutgroup
246     ne <- length(s)
247     o[NEXT:(NEXT + ne - 1L)] <- s
248
249     if (fuseRoot) {
250         phy$Nnode <- oldNnode - 1
251         N <- N - 1L
252     }
253     phy$edge[INV, ] <- phy$edge[INV, 2:1]
254     phy$edge <- phy$edge[o, ]
255     if (!is.null(phy$edge.length))
256         phy$edge.length <- phy$edge.length[o]
257
258     if (resolve.root) {
259         newnod <- oldNnode + n + 1
260         if (length(outgroup) == 1L) {
261             wh <- which(phy$edge[, 2] == outgroup)
262             phy$edge[1] <- newnod
263             phy$edge <-
264                 rbind(c(newroot, newnod), phy$edge[-wh, ], phy$edge[wh, ])
265             snw <- which(phy$edge[, 1] == newroot)
266             phy$edge[snw[length(snw) - 1], 1] <- newnod
267             if (!is.null(phy$edge.length)) {
268                 phy$edge.length <-
269                     c(0, phy$edge.length[-wh], phy$edge.length[wh])
270             }
271         } else {
272             wh <- which(phy$edge[, 1] == newroot)
273             phy$edge[wh[-1], 1] <- newnod
274             s1 <- 1:(wh[2] - 1)
275             s2 <- wh[2]:N
276             phy$edge <-
277                 rbind(phy$edge[s1, ], c(newroot, newnod), phy$edge[s2, ])
278             if (!is.null(phy$edge.length)) {
279                 tmp <- phy$edge.length[1]
280                 phy$edge.length[1] <- 0
281                 phy$edge.length <-
282                     c(phy$edge.length[s1], tmp, phy$edge.length[s2])
283             }
284         }
285         ## N <- N + 1L ... not needed
286         phy$Nnode <- phy$Nnode + 1
287     }
288
289     ## The block below renumbers the nodes so that they conform
290     ## to the "phylo" format
291     newNb <- integer(n + oldNnode)
292     newNb[newroot] <- n + 1L
293     sndcol <- phy$edge[, 2] > n
294     ## executed from right to left, so newNb is modified before phy$edge:
295     phy$edge[sndcol, 2] <- newNb[phy$edge[sndcol, 2]] <-
296         (n + 2):(n + phy$Nnode)
297     phy$edge[, 1] <- newNb[phy$edge[, 1]]
298
299     if (!is.null(phy$node.label)) {
300         #browser()
301         newNb <- newNb[-(1:n)]
302         if (fuseRoot) {
303             newNb <- newNb[-1]
304             phy$node.label <- phy$node.label[-1]
305         }
306         phy$node.label <- phy$node.label[order(newNb)]
307         if (resolve.root) {
308             phy$node.label[is.na(phy$node.label)] <- phy$node.label[1]
309             phy$node.label[1] <- NA
310             ##phy$node.label <- c(phy$node.label[1], NA, phy$node.label[-1])
311             ##phy$node.label <- c("NA", phy$node.label)
312         }
313     }
314     phy
315 }