Calculate only the upper triangle of the matrix

I have a vector:

v1 = c(1,2,3)

From this vector I want to create a matrix where the element in i,jwill be the sumelements of the vector at the positions i,j:

      [,1] [,2] [,3]
 [1,]    2    3    4
 [2,]    3    4    5
 [3,]    4    5    6

Questions

  • i,jand j,ithe same thing, so there is no reason to calculate 2x for better performance. How to achieve this?
  • How to create also a variant which will not calculate elements if i == jand just returns NAinstead? I am not asking for a command diag(m) <- NA, I am asking how to prevent the calculation of these elements.

PS . This is a smaller version of my problem.

+1
source share
2 answers

, , . , 1, , . , . ( ) :

f1 <- function(x){
    n <- length(x)
    m <- matrix(rep(x,n),n)
    m + t(m)
}
> f1(1:3)
      [,1] [,2] [,3]
[1,]    2    3    4
[2,]    3    4    5
[3,]    4    5    6

. , : , , .

f2 <- function(x){
    n <- length(x)
    m <- matrix(rep(NA,n^2),n)
    for(i in 1:(n-1)){
        for(j in (i+1):n) m[i,j] <- x[[i]] + x[[j]]
    }
    m
}
> f2(1:3)
      [,1] [,2] [,3]
[1,]   NA    3    4
[2,]   NA   NA    5
[3,]   NA   NA   NA

Benchmark:

library(microbenchmark)    
> microbenchmark(f1(1:100), f2(1:100))
Unit: microseconds
      expr       min         lq       mean    median        uq       max neval
 f1(1:100)   124.775   138.6175   181.6401   187.731   196.454   294.301   100
 f2(1:100) 10227.337 10465.1285 11000.1493 10616.830 10907.148 15826.259   100
+1

, , () R . C syadd ( ) R- , syadd.

/* symmetric add */
/* save this file as "syadd.c"*/

#include <R.h>
#include <Rinternals.h>

SEXP syadd (SEXP N, SEXP V, SEXP compute_diag) {
  int n = asInteger(N), diag = asInteger(compute_diag);
  /* initialize matrix X as a NA/NaN matrix */
  SEXP X = PROTECT(allocVector(REALSXP, n * n));
  double *x = REAL(X), *ptr_x = x, *v_end = x + n * n;
  while (ptr_x < v_end) *(ptr_x++) = NA_REAL;
  /* C interface */
  double *v = REAL(V), *vj = v, *vi, *vi_end = v, tmp;
  ptr_x = x; v_end = v + n;
  if (diag == 1) {
    /* compute upper triangular (including diagonal) */
    while (vj < v_end) {
      tmp = *vj;
      ptr_x = x; vi = v;
      while (vi <= vi_end) {
        *ptr_x = (*vi) * tmp;
        vi++; ptr_x++;
        }
      x += n; vi_end++; vj++;
      }
    } else {
    /* compute upper triangular only */
    while (vj < v_end) {
      tmp = *vj;
      ptr_x = x; vi = v;
      while (vi < vi_end) {
        *ptr_x = (*vi) * tmp;
        vi++; ptr_x++;
        }
      x += n; vi_end++; vj++;
      }
    }
 UNPROTECT(1);
 return X;
 }

R, (.so linux .dll windows). , Windows, linux:

R CMD SHLIB -c syadd.c

R:

## R wrapper function
syadd <- function (v, diag = TRUE) {
  n <- length(v); v <- as.numeric(v); diag <- as.integer(diag)
  ## load shared library
  dyn.load("syadd.so")
  X <- .Call("syadd", n, v, diag)
  ## add "dim" attribute to get a matrix rather than a vector
  attr(X, "dim") <- c(n, n)
  return(X)
  }

diag = FALSE, . R base:::outer:

## benchmarking
v <- 1:10000
system.time(syadd(v,diag = TRUE))
gc()
system.time(outer(v,v,"+"))
gc()

syadd 0.97s, 1.91s outer. , gc(), , .

:

  • , dyn.load(). inline cfunction. . R C - R.
  • , - Windows.
+1

All Articles