From 5ba1d7aaf1a5d088c1eeba61d4474fae31c8d1ec Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 29 Aug 2026 04:22:45 +0000 Subject: [PATCH 1/3] Optimize binomial log-likelihood calculation by removing ifelse --- .jules/bolt.md | 3 +++ R/llcont.R | 10 ++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index f658475..7b4cc2c 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -15,3 +15,6 @@ ## 2024-05-15 - [R Performance: ifelse Overhead] **Learning:** In R, ifelse evaluates both true and false branches entirely before subsetting, which is very inefficient for vector operations. **Action:** Optimize this by preallocating with res <- Y * 0 to preserve attributes and using vectorized subsetting like if any cond res subset <- ... +## 2026-08-11 - Fast Vectorized Subsetting over `ifelse()` +**Learning:** `ifelse(cond, true_branch, false_branch)` evaluates both branches entirely before subsetting, which creates significant overhead, especially in hot loops or likelihood calculations. Replacing it with vectorized subsetting (e.g. `res <- true_branch; res[!cond] <- false_branch`) is much faster and retains the same NA handling as `ifelse()`. Using `which()` for indices can alter NA behavior (since `which()` drops NAs) and must be carefully evaluated, but simple vectorized assignment is safe and highly performant. +**Action:** Replace `ifelse()` with vectorized assignment (e.g. `res <- a/b; res[b == 0] <- 0`) when optimizing hot loops or performance-critical likelihood paths. diff --git a/R/llcont.R b/R/llcont.R index d8e496a..7cc77d6 100644 --- a/R/llcont.R +++ b/R/llcont.R @@ -53,12 +53,18 @@ llcont.glm <- function(x, ...){ if(is.matrix(y)) { ## Bolt: replaced apply(..., 1, sum) with optimized rowSums() for performance n <- rowSums(y) - y <- ifelse(n == 0, 0, y[, 1]/n) + ## Bolt: replaced ifelse with vectorized subsetting for performance + y_new <- y[, 1]/n + y_new[n == 0] <- 0 + y <- y_new } else { n <- rep.int(1, length(y)) } m <- if (any(n > 1)) n else wt - wt <- ifelse(m > 0, (wt/m), 0) + ## Bolt: replaced ifelse with vectorized subsetting for performance + wt_new <- wt/m + wt_new[m <= 0] <- 0 + wt <- wt_new dbinom(round(m * y), round(m), mpreds, log = TRUE) * wt }, quasibinomial = { From c49c30eda53786fda96af3aafba07635b4332041 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 29 Aug 2026 04:38:43 +0000 Subject: [PATCH 2/3] Optimize binomial log-likelihood calculation by removing ifelse From e116e826b8b4da3d73879f458cdf251957684bcf Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sat, 29 Aug 2026 04:44:52 +0000 Subject: [PATCH 3/3] Optimize binomial log-likelihood calculation by removing ifelse