C способ обнаружения и «разделения» двоичного выражения

#r #c

#r #c

Вопрос:

У меня есть узкое место в моем коде в выражениях, например any(x >= b | x == y) , для большого x .

Я бы хотел избежать выделения x >= b | x == y . Я обнаружил, что легко написать функцию для конкретных случаев.

 SEXP eval_any_or2(SEXP x, SEXP b, SEXP y) {
  R_xlen_t N = xlength(x);
  if (xlength(y) != N || xlength(b) != 1) {
    error("Wrong lengths.");
  }
  const int *xp = INTEGER(x);
  const int *yp = INTEGER(y);
  const int *bp = INTEGER(b);
  
  bool o = false;
  
  for (R_xlen_t i = 0; i < N;   i) {
    if (xp[i] >= bp[0] || xp[i] == yp[i]) {
      o = true;
      break;
    }
  }
  SEXP ans = PROTECT(allocVector(LGLSXP, 1));
  LOGICAL(ans)[0] = o ? TRUE : FALSE;
  UNPROTECT(1);
  return ans;
}

 

Однако для ясности я бы хотел сохранить как можно больше естественного синтаксиса, например any_or(x >= b, x == y) . Поэтому я хотел бы иметь возможность определять, имеет ли вызов форму <vector> <operator> <vector> when <operator> является одним из стандартных двоичных операторов, и каждый <vector> из них имеет одинаковую длину векторов длины 1. Что-то вроде этого:

 any_or2 <- function(expr1, expr2) {
  sexp1 <- substitute(expr1)
  sexp2 <- substitute(expr2)
  if (!is_binary_sexp(sexp1) || !is_binary_sexp(sexp2) {
     # fall through to just basic R
     return(any(expr1 | expr2))
  }
  
  # In C
  eval_any_or2(...)  # either the substituted expression or x,y,b
}
 

Я попытался использовать следующую функцию C, которая определяет, является ли замещенное выражение / вызов двоичным выражением, но (а) у меня возникли проблемы с определением, является ли оператор двоичным оператором, и (б) получение векторов из выражения ( x , y , b в примере) для последующего использования (либо вта же функция C или переданная функции C, подобной приведенной выше).

 #define return_false SEXP ans = PROTECT(allocVector(LGLSXP, 1)); 
LOGICAL(ans)[0] = FALSE;                                         
UNPROTECT(1);                                                    
return ans;                                                      


SEXP is_binary_sexp(SEXP sx) {
  if (TYPEOF(sx) != LANGSXP) {
    return_false
  }
  // does it have three elements?
  int len = 0;
  SEXP el, nxt;
  for (nxt = sx; nxt != R_NilValue || len > 4; el = CAR(nxt), nxt = CDR(nxt)) {
    len  ;
  }
  if (len != 3) {
    return_false;
  }
  
  if (TYPEOF(CAR(sx)) != SYMSXP) {
    return_false;
  }
  
  SEXP ans = PROTECT(allocVector(LGLSXP, 1));
  LOGICAL(ans)[0] = TRUE;
  UNPROTECT(1);
  return ans;
}
 

В R я бы написал что-то вроде:

 is_binary_sexp_R <- function(sexprA) {
  # sexprA is the result of substitute()
  is.call(sexprA) amp;amp;
    length(sexprA) == 3L amp;amp;
    match(as.character(sexprA[[1]]), c("!=", "==", "<=", ">=", "<", ">"), nomatch = 0L) amp;amp;
    is.name(lhs <- sexprA[[2L]])
}
 

но я бы хотел сделать как можно больше на C.