The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.

05 - Logical Functions

0.1 Notes

0.2 Is any value in a vector ‘true’?

Base R’s any() function returns TRUE if there is at least one TRUE element in a vector, and FALSE otherwise. Below is one possible C++ implementation:

[[cpp4r::register]]
bool any_cpp(logicals x) {
  int n = x.size();
  
  for (int i = 0; i < n; ++i) {
    if (x[i]) {
      return true;
    }
  }
  return false;
}

Its R equivalent would be:

any_r <- function(x) {
  n <- length(x)
  
  for (i in 1:n) {
    if (x[i]) {
      return(TRUE)
    }
  }
  FALSE
}

Add and document the functions, update the package as in the previous vignettes, and then compare the functions speed with:

# install.packages("microbenchmark")
library(microbenchmark)
library(mypkg)

set.seed(123) # for reproducibility
x <- rpois(1e6, lambda = 2) # 1,000,000 elements
y <- ifelse(x > 2, TRUE, FALSE)

any(y)
any_cpp(y)
any_r(y)

microbenchmark(
  any(y),
  any_cpp(y),
  any_r(y)
)
Unit: nanoseconds
       expr min  lq mean median  uq   max neval cld
     any(y) 212 232  294    245 257  4320   100   a
 any_cpp(y) 810 833 1090    859 887 22900   100   a
   any_r(y) 746 822 1510    867 912 63300   100   a

0.3 Which elements in a vector are ‘true’?

Base R’s which() function returns the indices of the TRUE elements in a vector. Here is a possible C++ implementation:

[[cpp4r::register]]
integers which_cpp(logicals x) {
  int n = x.size();
  writable::integers res;
  int j = 0;

  for (int i = 0; i < n; ++i) {
    if (x[i]) {
      ++j;
      res.push_back(i + 1);
    }
  }

  if (j == 0) {
    return integers(0);
  } else {
    return res;
  }
}

Its R equivalent would be:

which_r <- function(x) {
  n <- length(x)
  res <- c()
  j <- 0

  for (i in 1:n) {
    if (x[i]) {
      res <- c(res, i)
      j <- j + 1
    }
  }

  if (j == 0) {
    return(0)
  } else {
    return(res)
  }
}

To test the functions, you can run the following benchmark code in the R console:

which(y[1:100])
which_cpp(y[1:100])
which_r(y[1:100])

microbenchmark(
  which(y[1:1000]),
  which_cpp(y[1:1000]),
  which_r(y[1:1000])
)
Unit: microseconds
                 expr    min     lq   mean median     uq   max neval cld
     which(y[1:1000])   6.30   7.08   8.27   7.75   8.86  20.2   100  a 
 which_cpp(y[1:1000])   8.52   9.93  11.90  10.90  12.00  72.1   100  a 
   which_r(y[1:1000]) 302.00 323.00 348.00 345.00 361.00 439.0   100  b

0.4 Are all values in a vector ‘true’?

Base R’s all() function checks if all elements in a vector are TRUE. Here is a possible C++ implementation that loops over the vector:

[[cpp4r::register]]
bool all_cpp_1(logicals x) {
  int n = x.size();
  for (int i = 0; i < n; ++i) {
    if (!x[i]) {
      return false;
    }
  }
  return true;
}

More concise C++ alternatives are:

[[cpp4r::register]]
bool all_cpp_2(logicals x) {
  for (int i = 0; i < x.size(); ++i) {
    if (!x[i]) {
      return false;
    }
  }
  return true;
}

[[cpp4r::register]] bool
all_cpp_3(logicals x) {
  for (bool i : x) {
    if (!i) {
      return false;
    }
  }
  return true;
}

[[cpp4r::register]] bool
all_cpp_4(logicals x) {
  return std::all_of(x.begin(), x.end(), [](bool x) { return x; });
}

To test the functions, you can run the following tests and benchmark code in the R console:

set.seed(123) # for reproducibility
x <- rpois(1e6, lambda = 2) # 1,000,000 elements

all(x > 2)
all_cpp_1(x > 2)
all_cpp_2(x > 2)
all_cpp_3(x > 2)
all_cpp_4(x > 2)

# also test the TRUE-only case
all(x >= 0)
all_cpp_1(x >= 0)
all_cpp_2(x >= 0)
all_cpp_3(x >= 0)
all_cpp_4(x >= 0)
microbenchmark(
  all(x > 2),
  all_cpp_1(x > 2),
  all_cpp_2(x > 2),
  all_cpp_3(x > 2),
  all_cpp_4(x > 2)
)
Unit: milliseconds
             expr  min   lq mean median   uq  max neval cld
       all(x > 2) 2.20 3.08 3.29   3.18 3.33 5.70   100   a
 all_cpp_1(x > 2) 2.24 3.14 3.38   3.23 3.35 5.57   100   a
 all_cpp_2(x > 2) 2.33 3.09 3.28   3.20 3.35 5.79   100   a
 all_cpp_3(x > 2) 2.22 3.13 3.41   3.25 3.39 5.91   100   a
 all_cpp_4(x > 2) 2.33 3.13 3.37   3.23 3.40 5.72   100   a

1 References

Vaughan D, Hester J, Francois R (2024). “Get started with cpp11.” https://cpp11.r-lib.org/articles/cpp11.html#intro.

These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.