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