Home > Blockchain >  Quickest way to sum over multiple powers in R
Quickest way to sum over multiple powers in R

Time:04-17

Given two vectors x,y of length d, what is the quickest way to compute

x[1] * y[1]   ...   x[d] * y[d]   x[1]^2 * y[1]^2   ...   x[d]^M * y[d]^M

Both d and M are large and I have a bunch of vectors for which this has to be done

CodePudding user response:

If x and y do not have any components equal to 1 then using the formula for the sum of terms of a geometric series we have the following which reduces the sum from 2M terms to 4 terms. Let z be x*y. Then

z   ...   z^M
= (z^(M 1) - x)/(z - 1)

For example,

M <- 3
x <- y <- 2:5

z <- x * y    
sum( (z^(M 1) - z) / (z - 1) )
## [1] 21546 


# check    
sum(z   z^2   z^3)
## [1] 21546 

If x and y can have components equal to 1 then use this:

M <- 3
x <- y <- 1:4

z <- x * y
sum(ifelse(z == 1, M, (z^(M 1) - z)/(z - 1)))
## [1] 5274

or

sum((z^(M 1) - z   M * (z == 1)) / (z - 1   (z == 1)))
## [1] 5274

# check
sum(x * y   x^2 * y^2   x^3 * y^3)
## [1] 5274

Benchmark

set.seed(123)

x <- runif(10000)
y <- runif(10000)
M <- 100

microbenchmark::microbenchmark(
  A = sum(sapply(seq(M), function(m) x^m * y^m)),
  B = {z <- x * y; sum((z^(M 1)-z M*(z==1))/(z-1 (z == 1))) }
)

Unit: milliseconds
 expr      min       lq       mean    median       uq      max neval cld
    A 209.0281 213.3180 238.843501 221.94970 238.1094 886.1139   100   b
    B   1.3416   1.3703   1.442492   1.39435   1.4391   2.2754   100  a 

Update

The original answer used where it should have been *. Have corrected. Note that it now runs even faster.

CodePudding user response:

Speed is unlikely to be a problem here, since you are carrying out simple arithmetic on two vectors. A concise way to write the code would be:

sum(sapply(seq(M), function(m) x^m * y^m))

In terms of speed, this will handle the sum of x and y vectors raised from the first to the hundredth power, even if x and y have a of length 10,000, in about 150 milliseconds:

x <- runif(10000)
y <- runif(10000)
M <- 100

f <- function() {
  sum(sapply(seq(M), function(m) x^m * y^m))
}

microbenchmark::microbenchmark(f())
#> Unit: milliseconds
#>  expr      min       lq     mean   median       uq      max neval
#>   f() 142.1891 145.1826 161.8941 151.1814 163.7553 347.8592   100

Created on 2022-04-16 by the reprex package (v2.0.1)

  •  Tags:  
  • r
  • Related