# This is intended only for symmetric matrices, until possibly replaced by
# Cholesky factorization.
matsqrt <-
  function(mat, tol = 0, symmetric = TRUE){
    stopifnot(is.numeric(mat), is.numeric(tol), length(tol) == 1, tol <= 0)
    if(is.matrix(mat)){
      if(all(dim(mat) == 1)){
        # Note: this is needed when p = 1, in which case J^tJ is 1x1.
        output <- sqrt(mat)
      } else{
        stopifnot(identical(diff(dim(mat)), 0L))
        eig <- tryCatch(eigen(mat, symmetric = symmetric),
                        error = function(e) stop("Unable to compute eigendecomposition of ",
                                                 deparse1(substitute(mat)), ": ", e))
        stopifnot(is.double(eig[["values"]]), is.double(eig[["vectors"]]),
                  all(eig[["values"]] >= tol))
        e_vals <- pmax(0, eig[["values"]])
        output <- eig[["vectors"]] %*% (sqrt(e_vals) * t(eig[["vectors"]]))
      }
    } else {
      # This allows covariance specification in the form of a single numeric
      # value.
      stopifnot(all(mat > 0))
      output <- sqrt(mat)
    }
    return(output)
  }
