R/cophenetic.phylo.R

## cophenetic.phylo.R (2010-11-15)

##   Pairwise Distances from a Phylogenetic Tree

## Copyright 2006-2010 Emmanuel Paradis

## This file is part of the R-package `ape'.
## See the file ../COPYING for licensing issues.

dist.nodes <- function(x)
{
    if (is.null(x$edge.length))
        stop("your tree has no branch lengths")

    trim <- FALSE
    if (!is.binary.tree(x) || !is.rooted(x)) {
        trim <- TRUE
        x <- makeNodeLabel(x)
        x <- multi2di(x, random = FALSE)
    }

    n <- length(x$tip.label)
    n.node <- x$Nnode
    N <- n + n.node
    x <- reorder(x, order = "pruningwise")

    res <- matrix(NA, N, N)
    res[cbind(1:N, 1:N)] <- 0 # implicit mode conversion

    ## I like the simplicity of this one:
    res[x$edge] <- res[x$edge[, 2:1]] <- x$edge.length

    ## compute the distances ...
    for (i in seq(from = 1, by = 2, length.out = n.node)) {
        j <- i + 1
        anc <- x$edge[i, 1]
        des1 <- x$edge[i, 2]
        des2 <- x$edge[j, 2]

        ## If `des1' is a node, we look for the nodes and tips for
        ## which the distance up to `des1' has already been
        ## computed, including `des1' itself. For all these, we can
        ## compute the distance up to `anc' and all node(s) and
        ## tip(s) in `des2'.
        if (des1 > n) des1 <- which(!is.na(res[des1, ]))

        ## id. for `des2'
        if (des2 > n) des2 <- which(!is.na(res[des2, ]))

        ## The following expression is vectorized only on `des2' and
        ## not on `des1' because they may be of different lengths.
        for (y in des1)
          res[y, des2] <- res[des2, y] <- res[anc, y] + res[anc, des2]
        ## compute the distances between the tip(s) and node(s)
        ## in `des2' and the ancestor of `anc'; id. for `des2'
        ## (only if it is not the root)
        if (anc != n + 1) {
            ind <- which(x$edge[, 2] == anc)
            nod <- x$edge[ind, 1] # the ancestor of `anc'
            l <- x$edge.length[ind]
            res[des2, nod] <- res[nod, des2] <- res[anc, des2] + l
            res[des1, nod] <- res[nod, des1] <- res[anc, des1] + l
        }
    }
    if (trim) {
        i <- which(x$node.label == "") + n
        res <- res[-i, -i]
        N <- dim(res)[1]
    }
    dimnames(res)[1:2] <- list(1:N)
    res
}

cophenetic.phylo <- function(x)
{
    n <- length(x$tip.label)
    ans <- dist.nodes(x)[1:n, 1:n]
    dimnames(ans)[1:2] <- list(x$tip.label)
    ans
}
gjuggler/ape documentation built on May 17, 2019, 6:03 a.m.