]> git.donarmstrong.com Git - ape.git/blob - R/chronopl.R
a few bug fixes especially in plot.phylo()
[ape.git] / R / chronopl.R
1 ## chronopl.R (2009-07-06)
2
3 ##   Molecular Dating With Penalized Likelihood
4
5 ## Copyright 2005-2009 Emmanuel Paradis
6
7 ## This file is part of the R-package `ape'.
8 ## See the file ../COPYING for licensing issues.
9
10 chronopl <-
11     function(phy, lambda, age.min = 1, age.max = NULL,
12              node = "root", S = 1, tol = 1e-8,
13              CV = FALSE, eval.max = 500, iter.max = 500, ...)
14 {
15     n <- length(phy$tip.label)
16     ROOT <- n + 1
17     if (length(node) == 1 && node == "root") node <- ROOT
18     if (any(node <= n))
19         stop("node numbers should be greater than the number of tips")
20     zerobl <- which(phy$edge.length <= 0)
21     if (length(zerobl)) {
22         if (any(phy$edge[zerobl, 2] <= n))
23             stop("at least one terminal branch is of length zero:
24   you should remove it to have a meaningful estimation.")
25         else {
26             warning("at least one internal branch is of length zero:
27   it was collapsed and some nodes have been deleted.")
28             if (length(node) == 1 && node == ROOT)
29                 phy <- di2multi(phy)
30             else {
31                 tmp <- FALSE
32                 if (is.null(phy$node.label)) {
33                     tmp <- !tmp
34                     phy$node.label <- paste("node", 1:phy$Nnode)
35                 }
36                 node.lab <- phy$node.label[node - n]
37                 phy <- di2multi(phy)
38                 node <- match(node.lab, phy$node.label) + n
39                 if (tmp) phy$node.label <- NULL
40             }
41         }
42     }
43     m <- phy$Nnode
44     el <- phy$edge.length
45     e <- phy$edge
46     N <- dim(e)[1]
47     TIPS <- 1:n
48     EDGES <- 1:N
49
50     ini.rate <- el
51     el <- el/S
52
53     ## `basal' contains the indices of the basal edges
54     ## (ie, linked to the root):
55     basal <- which(e[, 1] == ROOT)
56     Nbasal <- length(basal)
57
58     ## `ind' contains in its 1st column the index of all nonbasal
59     ## edges, and in its second column the index of the edges
60     ## where these edges come from (ie, this matrix contains pairs
61     ## of contiguous edges), eg:
62
63     ##         ___b___    ind:
64     ##        |           |   |   |
65     ## ___a___|           | b | a |
66     ##        |           | c | a |
67     ##        |___c___    |   |   |
68
69     ind <- matrix(0L, N - Nbasal, 2)
70     ind[, 1] <- EDGES[-basal]
71     ind[, 2] <- match(e[EDGES[-basal], 1], e[, 2])
72
73     age <- numeric(n + m)
74
75     ##ini.time <- node.depth(phy)[-TIPS] - 1
76     ini.time <- node.depth(phy) - 1
77
78     ## first, rescale all times with respect to
79     ## the age of the 1st element of `node':
80     ratio <- age.min[1]/ini.time[node[1]]
81     ini.time <- ini.time*ratio
82
83     if (length(node) > 1) {
84         ini.time[node] <- age.min
85         real.edge.length <- ini.time[e[, 1]] - ini.time[e[, 2]]
86         while (any(real.edge.length <= 0)) {
87             for (i in EDGES) {
88                 if (real.edge.length[i] > 0) next
89                 if (e[i, 1] %in% node) {
90                     ini.time[e[i, 2]] <- ini.time[e[1, 2]] - 2 * real.edge.length[i]
91                     next
92                 }
93                 if (e[i, 2] %in% node) {
94                     ini.time[e[i, 1]] <- ini.time[e[1, 1]] + 2 * real.edge.length[i]
95                     next
96                 }
97                 browser()
98                 ini.time[e[i, 2]] <- ini.time[e[1, 2]] - real.edge.length[i]
99                 ini.time[e[i, 1]] <- ini.time[e[1, 1]] + real.edge.length[i]
100             }
101             real.edge.length <- ini.time[e[, 1]] - ini.time[e[, 2]]
102             print(min(real.edge.length))
103         }
104     }
105     ## `unknown.ages' will contain the index of the nodes of unknown age:
106     unknown.ages <- n + 1:m
107
108     ## define the bounds for the node ages:
109     lower <- rep(tol, length(unknown.ages))
110     upper <- rep(1/tol, length(unknown.ages))
111
112     if (!is.null(age.max)) { # are some nodes known within some intervals?
113         lower[node - n] <- age.min
114         upper[node - n] <- age.max
115         interv <- which(age.min != age.max)
116         node <- node[-interv]
117         if (length(node)) age[node] <- age.min[-interv]
118     } else age[node] <- age.min
119
120     if (length(node)) {
121         unknown.ages <- unknown.ages[n - node]
122         lower <- lower[n - node]
123         upper <- upper[n - node]
124     }
125
126     ## `known.ages' contains the index of all nodes (internal and
127     ## terminal) of known age:
128     known.ages <- c(TIPS, node)
129
130     ## concatenate the bounds for the rates:
131     lower <- c(rep(tol, N), lower)
132     upper <- c(rep(1 - tol, N), upper)
133
134     minusploglik.gr <- function(rate, node.time) {
135         grad <- numeric(N + length(unknown.ages))
136         age[unknown.ages] <- node.time
137         real.edge.length <- age[e[, 1]] - age[e[, 2]]
138         if (any(real.edge.length < 0)) {
139             grad[] <- 0
140             return(grad)
141         }
142         ## gradient for the rates:
143         ## the parametric part can be calculated without a loop:
144         grad[EDGES] <- real.edge.length - el/rate
145         if (Nbasal == 2) { # the simpler formulae if there's a basal dichotomy
146             grad[basal[1]] <-
147                 grad[basal[1]] + lambda*(rate[basal[1]] - rate[basal[2]])
148             grad[basal[2]] <-
149                 grad[basal[2]] + lambda*(rate[basal[2]] - rate[basal[1]])
150         } else { # the general case
151             for (i in 1:Nbasal)
152                 grad[basal[i]] <- grad[basal[i]] +
153                     lambda*(2*rate[basal[i]]*(1 - 1/Nbasal) -
154                             2*sum(rate[basal[-i]])/Nbasal)/(Nbasal - 1)
155         }
156
157         for (i in EDGES) {
158             ii <- c(which(e[, 2] == e[i, 1]), which(e[, 1] == e[i, 2]))
159             if (!length(ii)) next
160             grad[i] <- grad[i] + lambda*(2*length(ii)*rate[i] - 2*sum(rate[ii]))
161         }
162
163         ## gradient for the 'node times'
164         for (i in 1:length(unknown.ages)) {
165             nd <- unknown.ages[i]
166             ii <- which(e[, 1] == nd)
167             grad[i + N] <-
168                 sum(rate[ii] - el[ii]/real.edge.length[ii])#, na.rm = TRUE)
169             if (nd != ROOT) {
170                 ii <- which(e[, 2] == nd)
171                 grad[i + N] <- grad[i + N] -
172                     rate[ii] + el[ii]/real.edge.length[ii]
173             }
174         }
175         grad
176     }
177
178     minusploglik <- function(rate, node.time) {
179         age[unknown.ages] <- node.time
180         real.edge.length <- age[e[, 1]] - age[e[, 2]]
181         if (any(real.edge.length < 0)) return(1e50)
182         B <- rate*real.edge.length
183         loglik <- sum(-B + el*log(B) - lfactorial(el))
184         -(loglik - lambda*(sum((rate[ind[, 1]] - rate[ind[, 2]])^2)
185                            + var(rate[basal])))
186     }
187
188     out <- nlminb(c(ini.rate, ini.time[unknown.ages]),
189                   function(p) minusploglik(p[EDGES], p[-EDGES]),
190                   function(p) minusploglik.gr(p[EDGES], p[-EDGES]),
191                   control = list(eval.max = eval.max, iter.max = iter.max, ...),
192                   lower = lower, upper = upper)
193
194     attr(phy, "ploglik") <- -out$objective
195     attr(phy, "rates") <- out$par[EDGES]
196     attr(phy, "message") <- out$message
197     age[unknown.ages] <- out$par[-EDGES]
198     if (CV) ophy <- phy
199     phy$edge.length <- age[e[, 1]] - age[e[, 2]]
200     if (CV) attr(phy, "D2") <-
201         chronopl.cv(ophy, lambda, age.min, age.max, node,
202                     n, S, tol, eval.max, iter.max, ...)
203     phy
204 }
205
206 chronopl.cv <- function(ophy, lambda, age.min, age.max, nodes,
207                         n, S, tol, eval.max, iter.max, ...)
208 ### ophy: the original phylogeny
209 ### n: number of tips
210 ### Note that we assume here that the order of the nodes
211 ### in node.label are not modified by the drop.tip operation
212 {
213     cat("Doing cross-validation\n")
214     BT <- branching.times(ophy)
215     D2 <- numeric(n)
216
217     cat("  dropping tip")
218     for (i in 1:n) {
219         cat(" ", i, sep = "")
220         tr <- drop.tip(ophy, i)
221         j <- which(ophy$edge[, 2] == i)
222         if (ophy$edge[j, 1] %in% nodes) {
223             k <- which(nodes == ophy$edge[j, 1])
224             node <- nodes[-k]
225             agemin <- age.min[-k]
226             agemax <- age.max[-k]
227         } else node <- nodes
228         if (length(node)) {
229             chr <- chronopl(tr, lambda, age.min, age.max, node,
230                             S, tol, FALSE, eval.max, iter.max, ...)
231             tmp <-
232                 if (Nnode(chr) == Nnode(ophy)) BT else BT[-(ophy$edge[j, 1] - n)]
233             D2[i] <- sum((tmp - branching.times(chr))^2 / tmp)
234         } else D2[i] <- 0
235     }
236     cat("\n")
237     D2
238 }