From d8346585abc41d7966ca67b013f19db71b8b1470 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 2 Aug 2026 16:10:52 +0000 Subject: [PATCH 1/4] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Replace=202D=20datafram?= =?UTF-8?q?e=20assignments=20with=201D=20vector=20indexing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ’‘ What: Changed expressions like `NewScaleParms[idx, "est"] <- FALSE` to `NewScaleParms$est[idx] <- FALSE` across `R/aFIPC.R`. 🎯 Why: Modifying a dataframe via 2D matrix subsetting in R dispatches to the expensive `[<-.data.frame` method, which involves dimensionality checks, attributes preservation, and factor checking. 1D vector subsetting accesses the list element directly and assigns it at the C level, running drastically faster while achieving exactly the same outcome. πŸ“Š Impact: Speeds up parameter assignment and modification loops during heavy item linking tasks. Expected reduction in execution time for large iterative operations. πŸ”¬ Measurement: Run the test suite and observe no functional regressions with standard datasets. Compare `microbenchmark::microbenchmark(df[1, "x"] <- 1, df$x[1] <- 1)` for direct measurement. --- .jules/bolt.md | 3 +++ R/aFIPC.R | 36 ++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/.jules/bolt.md b/.jules/bolt.md index 7d3c603..7261b17 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -16,3 +16,6 @@ ## 2025-02-12 - R μ–Έμ–΄μ—μ„œ 반볡적인 mirt λͺ¨λΈ 생성 μ‹œ λΆˆν•„μš”ν•œ λ°μ΄ν„°ν”„λ ˆμž„ λΆ€λΆ„μ§‘ν•© μΆ”μΆœ μ΅œμ ν™” **Learning:** Rμ—μ„œ λ°μ΄ν„°ν”„λ ˆμž„μ˜ νŠΉμ • 열을 μΆ”μΆœν•˜λŠ” μž‘μ—…(`df[cols]`)은 O(N)의 λ©”λͺ¨λ¦¬ 볡사λ₯Ό μˆ˜λ°˜ν•©λ‹ˆλ‹€. `autoFIPC`μ—μ„œ `mirt` λͺ¨λΈμ˜ νŒŒλΌλ―Έν„°λ₯Ό μ„€μ •ν•˜κ±°λ‚˜ ν˜ΈμΆœν•˜λŠ” κ³Όμ • 쀑에 `newformXDataK[colnames(newFormModel@Data$data)]` μ½”λ“œκ°€ λ°˜λ³΅ν•΄μ„œ μ‚¬μš©λ˜μ—ˆκ³ , 심지어 `ncol()`을 μœ„ν•΄ λ‹¨μˆœνžˆ 개수λ₯Ό ꡬ할 λ•Œλ„ μ‚¬μš©λ˜μ–΄ λΆˆν•„μš”ν•œ λ©”λͺ¨λ¦¬ ν• λ‹Ήκ³Ό μ˜€λ²„ν—€λ“œλ₯Ό μ΄ˆλž˜ν–ˆμŠ΅λ‹ˆλ‹€. **Action:** μ‘°κ±΄λ¬Έμ΄λ‚˜ 반볡문 λ‚΄λΆ€μ—μ„œ λΆˆν•„μš”ν•˜κ²Œ λ°μ΄ν„°ν”„λ ˆμž„ λΆ€λΆ„μ§‘ν•© 연산이 λ°˜λ³΅λ˜μ§€ μ•Šλ„λ‘ μ™ΈλΆ€μ—μ„œ ν•œ 번만 `linkedFormData <- newformXDataK[colnames(newFormModel@Data$data)]`둜 캐싱(caching)ν•œ λ’€, `ncol(linkedFormData)`와 `data = linkedFormData` ν˜•νƒœλ‘œ μž¬μ‚¬μš©ν•˜μ—¬ λ©”λͺ¨λ¦¬ 볡사와 O(N) μ˜€λ²„ν—€λ“œλ₯Ό λ°©μ§€ν•΄μ•Ό ν•©λ‹ˆλ‹€. +## 2025-02-13 - R μ–Έμ–΄μ—μ„œ λ°μ΄ν„°ν”„λ ˆμž„ μ›μ†Œ μˆ˜μ • μ‹œ 1D 벑터 인덱싱을 ν†΅ν•œ μ΅œμ ν™” +**Learning:** Rμ—μ„œ 데이터 ν”„λ ˆμž„μ˜ 일뢀 μ›μ†Œλ₯Ό λ³€κ²½ν•  λ•Œ `df[idx, "col"] <- val`와 같은 2D 맀트릭슀 ν˜•νƒœμ˜ 인덱싱을 μ‚¬μš©ν•˜λ©΄ λ‚΄λΆ€μ μœΌλ‘œ λ³΅μž‘ν•œ `[<-.data.frame` λ©”μ†Œλ“œκ°€ ν˜ΈμΆœλ˜μ–΄ 차원 검사 및 μš”μ†Œ νƒ€μž… 확인 λ“±μ˜ 좔가적인 μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•˜λ©° μ„±λŠ₯이 크게 μ €ν•˜λ©λ‹ˆλ‹€. +**Action:** 데이터 ν”„λ ˆμž„ μ›μ†Œλ₯Ό λ³€κ²½ν•  λ•ŒλŠ” `df$col[idx] <- val`와 같이 1D 벑터 인덱싱(리슀트 μΆ”μΆœ ν›„ μˆ˜μ •)을 μ‚¬μš©ν•˜λ©΄ `[<-.data.frame` λ©”μ†Œλ“œ ν˜ΈμΆœμ„ μš°νšŒν•˜κ³  벑터 μš”μ†Œμ— 직접 O(1) μˆ˜μ€€μœΌλ‘œ λΉ λ₯΄κ²Œ μ ‘κ·Όν•  수 μžˆμœΌλ―€λ‘œ, ν• λ‹Ή(assignment) μ‹œ 이 방식을 κ°•μ œν•΄μ•Ό ν•©λ‹ˆλ‹€. diff --git a/R/aFIPC.R b/R/aFIPC.R index 6254651..bebfe79 100644 --- a/R/aFIPC.R +++ b/R/aFIPC.R @@ -598,15 +598,15 @@ autoFIPC <- # Preserve mirt's structural estimability flags. Forcing every row TRUE # frees boundary parameters such as 2PL g/u and makes the Hessian unstable. - NewScaleParms[NewScaleParms$item == 'GROUP', "est"] <- FALSE - OldScaleParms[OldScaleParms$item == 'GROUP', "est"] <- FALSE + NewScaleParms$est[NewScaleParms$item == 'GROUP'] <- FALSE + OldScaleParms$est[OldScaleParms$item == 'GROUP'] <- FALSE - NewScaleParms[NewScaleParms$name == "COV_11", "est"] <- TRUE - OldScaleParms[OldScaleParms$name == "COV_11", "est"] <- TRUE + NewScaleParms$est[NewScaleParms$name == "COV_11"] <- TRUE + OldScaleParms$est[OldScaleParms$name == "COV_11"] <- TRUE if (itemtype == 'Rasch') { - NewScaleParms[NewScaleParms$name == "a1", "est"] <- FALSE - OldScaleParms[OldScaleParms$name == "a1", "est"] <- FALSE + NewScaleParms$est[NewScaleParms$name == "a1"] <- FALSE + OldScaleParms$est[OldScaleParms$name == "a1"] <- FALSE } #IPD @@ -789,11 +789,11 @@ autoFIPC <- message(' Newform Parms: ', paste(NewScaleParms[newIdx, "value"], collapse = ' ')) message(' Oldform Parms: ', paste(OldScaleParms[oldIdx, "value"], collapse = ' ')) - NewScaleParms[newIdx, "value"] <- + NewScaleParms$value[newIdx] <- OldScaleParms[oldIdx, "value"] message(' Linkedform Parms: ', paste(NewScaleParms[newIdx, "value"], collapse = ' '), '\n') - NewScaleParms[newIdx, "est"] <- + NewScaleParms$est[newIdx] <- FALSE } else { message( @@ -813,9 +813,9 @@ autoFIPC <- newBetaIdx <- NewScaleParms$item == 'BETA' oldBetaIdx <- OldScaleParms$item == 'BETA' - NewScaleParms[newBetaIdx, "value"] <- + NewScaleParms$value[newBetaIdx] <- OldScaleParms[oldBetaIdx, "value"] - NewScaleParms[newBetaIdx, "est"] <- + NewScaleParms$est[newBetaIdx] <- FALSE message('applying BETA parameter as linking') @@ -858,13 +858,13 @@ autoFIPC <- new_mean11_idx <- NewScaleParms$name == "MEAN_11" old_mean11_idx <- OldScaleParms$name == "MEAN_11" - NewScaleParms[new_cov11_idx, "est"] <- FALSE - OldScaleParms[old_cov11_idx, "est"] <- FALSE - NewScaleParms[new_mean11_idx, "est"] <- FALSE - OldScaleParms[old_mean11_idx, "est"] <- FALSE + NewScaleParms$est[new_cov11_idx] <- FALSE + OldScaleParms$est[old_cov11_idx] <- FALSE + NewScaleParms$est[new_mean11_idx] <- FALSE + OldScaleParms$est[old_mean11_idx] <- FALSE - NewScaleParms[new_cov11_idx, "value"] <- 1 - OldScaleParms[old_mean11_idx, "value"] <- 0 + NewScaleParms$value[new_cov11_idx] <- 1 + OldScaleParms$value[old_mean11_idx] <- 0 } if (freeMEAN == T) { LinkedModelSyntax <- @@ -875,8 +875,8 @@ autoFIPC <- 'MEAN = F1' )) - NewScaleParms[NewScaleParms$name == "MEAN_1", "est"] <- TRUE - OldScaleParms[OldScaleParms$name == "MEAN_1", "est"] <- TRUE + NewScaleParms$est[NewScaleParms$name == "MEAN_1"] <- TRUE + OldScaleParms$est[OldScaleParms$name == "MEAN_1"] <- TRUE } else { LinkedModelSyntax <- mirt::mirt.model(paste0( From aad97c23c0919e762bbfa376f23b8b873de0ada0 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 2 Aug 2026 16:16:24 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Replace=202D=20datafram?= =?UTF-8?q?e=20assignments=20with=201D=20vector=20indexing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ’‘ What: Changed expressions like `NewScaleParms[idx, "est"] <- FALSE` to `NewScaleParms$est[idx] <- FALSE` across `R/aFIPC.R`. 🎯 Why: Modifying a dataframe via 2D matrix subsetting in R dispatches to the expensive `[<-.data.frame` method, which involves dimensionality checks, attributes preservation, and factor checking. 1D vector subsetting accesses the list element directly and assigns it at the C level, running drastically faster while achieving exactly the same outcome. πŸ“Š Impact: Speeds up parameter assignment and modification loops during heavy item linking tasks. Expected reduction in execution time for large iterative operations. πŸ”¬ Measurement: Run the test suite and observe no functional regressions with standard datasets. Compare `microbenchmark::microbenchmark(df[1, "x"] <- 1, df$x[1] <- 1)` for direct measurement. From 3f4bebb38eafd8f8ef1c2edff58823f2e25b1423 Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 2 Aug 2026 16:43:21 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Replace=202D=20datafram?= =?UTF-8?q?e=20assignments=20with=201D=20vector=20indexing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ’‘ What: Changed expressions like `NewScaleParms[idx, "est"] <- FALSE` to `NewScaleParms$est[idx] <- FALSE` across `R/aFIPC.R`. Added `.semgrepignore` to `.Rbuildignore`. 🎯 Why: Modifying a dataframe via 2D matrix subsetting in R dispatches to the expensive `[<-.data.frame` method, which involves dimensionality checks, attributes preservation, and factor checking. 1D vector subsetting accesses the list element directly and assigns it at the C level, running drastically faster while achieving exactly the same outcome. Including `.semgrepignore` in `.Rbuildignore` fixes the R CMD check failing due to a hidden file error. πŸ“Š Impact: Speeds up parameter assignment and modification loops during heavy item linking tasks. Expected reduction in execution time for large iterative operations. Fixes CI failures. πŸ”¬ Measurement: Run the test suite and observe no functional regressions with standard datasets. Compare `microbenchmark::microbenchmark(df[1, "x"] <- 1, df$x[1] <- 1)` for direct measurement. --- .Rbuildignore | 1 + .jules/bolt.md | 3 --- R/aFIPC.R | 36 ++++++++++++++++++------------------ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index 232504f..388f1c6 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -22,3 +22,4 @@ ^\.jules(/.*)?$ ^\.trivyignore\.yaml$ ^trivy\.yaml$ +^\.semgrepignore$ diff --git a/.jules/bolt.md b/.jules/bolt.md index 7261b17..7d3c603 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -16,6 +16,3 @@ ## 2025-02-12 - R μ–Έμ–΄μ—μ„œ 반볡적인 mirt λͺ¨λΈ 생성 μ‹œ λΆˆν•„μš”ν•œ λ°μ΄ν„°ν”„λ ˆμž„ λΆ€λΆ„μ§‘ν•© μΆ”μΆœ μ΅œμ ν™” **Learning:** Rμ—μ„œ λ°μ΄ν„°ν”„λ ˆμž„μ˜ νŠΉμ • 열을 μΆ”μΆœν•˜λŠ” μž‘μ—…(`df[cols]`)은 O(N)의 λ©”λͺ¨λ¦¬ 볡사λ₯Ό μˆ˜λ°˜ν•©λ‹ˆλ‹€. `autoFIPC`μ—μ„œ `mirt` λͺ¨λΈμ˜ νŒŒλΌλ―Έν„°λ₯Ό μ„€μ •ν•˜κ±°λ‚˜ ν˜ΈμΆœν•˜λŠ” κ³Όμ • 쀑에 `newformXDataK[colnames(newFormModel@Data$data)]` μ½”λ“œκ°€ λ°˜λ³΅ν•΄μ„œ μ‚¬μš©λ˜μ—ˆκ³ , 심지어 `ncol()`을 μœ„ν•΄ λ‹¨μˆœνžˆ 개수λ₯Ό ꡬ할 λ•Œλ„ μ‚¬μš©λ˜μ–΄ λΆˆν•„μš”ν•œ λ©”λͺ¨λ¦¬ ν• λ‹Ήκ³Ό μ˜€λ²„ν—€λ“œλ₯Ό μ΄ˆλž˜ν–ˆμŠ΅λ‹ˆλ‹€. **Action:** μ‘°κ±΄λ¬Έμ΄λ‚˜ 반볡문 λ‚΄λΆ€μ—μ„œ λΆˆν•„μš”ν•˜κ²Œ λ°μ΄ν„°ν”„λ ˆμž„ λΆ€λΆ„μ§‘ν•© 연산이 λ°˜λ³΅λ˜μ§€ μ•Šλ„λ‘ μ™ΈλΆ€μ—μ„œ ν•œ 번만 `linkedFormData <- newformXDataK[colnames(newFormModel@Data$data)]`둜 캐싱(caching)ν•œ λ’€, `ncol(linkedFormData)`와 `data = linkedFormData` ν˜•νƒœλ‘œ μž¬μ‚¬μš©ν•˜μ—¬ λ©”λͺ¨λ¦¬ 볡사와 O(N) μ˜€λ²„ν—€λ“œλ₯Ό λ°©μ§€ν•΄μ•Ό ν•©λ‹ˆλ‹€. -## 2025-02-13 - R μ–Έμ–΄μ—μ„œ λ°μ΄ν„°ν”„λ ˆμž„ μ›μ†Œ μˆ˜μ • μ‹œ 1D 벑터 인덱싱을 ν†΅ν•œ μ΅œμ ν™” -**Learning:** Rμ—μ„œ 데이터 ν”„λ ˆμž„μ˜ 일뢀 μ›μ†Œλ₯Ό λ³€κ²½ν•  λ•Œ `df[idx, "col"] <- val`와 같은 2D 맀트릭슀 ν˜•νƒœμ˜ 인덱싱을 μ‚¬μš©ν•˜λ©΄ λ‚΄λΆ€μ μœΌλ‘œ λ³΅μž‘ν•œ `[<-.data.frame` λ©”μ†Œλ“œκ°€ ν˜ΈμΆœλ˜μ–΄ 차원 검사 및 μš”μ†Œ νƒ€μž… 확인 λ“±μ˜ 좔가적인 μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•˜λ©° μ„±λŠ₯이 크게 μ €ν•˜λ©λ‹ˆλ‹€. -**Action:** 데이터 ν”„λ ˆμž„ μ›μ†Œλ₯Ό λ³€κ²½ν•  λ•ŒλŠ” `df$col[idx] <- val`와 같이 1D 벑터 인덱싱(리슀트 μΆ”μΆœ ν›„ μˆ˜μ •)을 μ‚¬μš©ν•˜λ©΄ `[<-.data.frame` λ©”μ†Œλ“œ ν˜ΈμΆœμ„ μš°νšŒν•˜κ³  벑터 μš”μ†Œμ— 직접 O(1) μˆ˜μ€€μœΌλ‘œ λΉ λ₯΄κ²Œ μ ‘κ·Όν•  수 μžˆμœΌλ―€λ‘œ, ν• λ‹Ή(assignment) μ‹œ 이 방식을 κ°•μ œν•΄μ•Ό ν•©λ‹ˆλ‹€. diff --git a/R/aFIPC.R b/R/aFIPC.R index bebfe79..6254651 100644 --- a/R/aFIPC.R +++ b/R/aFIPC.R @@ -598,15 +598,15 @@ autoFIPC <- # Preserve mirt's structural estimability flags. Forcing every row TRUE # frees boundary parameters such as 2PL g/u and makes the Hessian unstable. - NewScaleParms$est[NewScaleParms$item == 'GROUP'] <- FALSE - OldScaleParms$est[OldScaleParms$item == 'GROUP'] <- FALSE + NewScaleParms[NewScaleParms$item == 'GROUP', "est"] <- FALSE + OldScaleParms[OldScaleParms$item == 'GROUP', "est"] <- FALSE - NewScaleParms$est[NewScaleParms$name == "COV_11"] <- TRUE - OldScaleParms$est[OldScaleParms$name == "COV_11"] <- TRUE + NewScaleParms[NewScaleParms$name == "COV_11", "est"] <- TRUE + OldScaleParms[OldScaleParms$name == "COV_11", "est"] <- TRUE if (itemtype == 'Rasch') { - NewScaleParms$est[NewScaleParms$name == "a1"] <- FALSE - OldScaleParms$est[OldScaleParms$name == "a1"] <- FALSE + NewScaleParms[NewScaleParms$name == "a1", "est"] <- FALSE + OldScaleParms[OldScaleParms$name == "a1", "est"] <- FALSE } #IPD @@ -789,11 +789,11 @@ autoFIPC <- message(' Newform Parms: ', paste(NewScaleParms[newIdx, "value"], collapse = ' ')) message(' Oldform Parms: ', paste(OldScaleParms[oldIdx, "value"], collapse = ' ')) - NewScaleParms$value[newIdx] <- + NewScaleParms[newIdx, "value"] <- OldScaleParms[oldIdx, "value"] message(' Linkedform Parms: ', paste(NewScaleParms[newIdx, "value"], collapse = ' '), '\n') - NewScaleParms$est[newIdx] <- + NewScaleParms[newIdx, "est"] <- FALSE } else { message( @@ -813,9 +813,9 @@ autoFIPC <- newBetaIdx <- NewScaleParms$item == 'BETA' oldBetaIdx <- OldScaleParms$item == 'BETA' - NewScaleParms$value[newBetaIdx] <- + NewScaleParms[newBetaIdx, "value"] <- OldScaleParms[oldBetaIdx, "value"] - NewScaleParms$est[newBetaIdx] <- + NewScaleParms[newBetaIdx, "est"] <- FALSE message('applying BETA parameter as linking') @@ -858,13 +858,13 @@ autoFIPC <- new_mean11_idx <- NewScaleParms$name == "MEAN_11" old_mean11_idx <- OldScaleParms$name == "MEAN_11" - NewScaleParms$est[new_cov11_idx] <- FALSE - OldScaleParms$est[old_cov11_idx] <- FALSE - NewScaleParms$est[new_mean11_idx] <- FALSE - OldScaleParms$est[old_mean11_idx] <- FALSE + NewScaleParms[new_cov11_idx, "est"] <- FALSE + OldScaleParms[old_cov11_idx, "est"] <- FALSE + NewScaleParms[new_mean11_idx, "est"] <- FALSE + OldScaleParms[old_mean11_idx, "est"] <- FALSE - NewScaleParms$value[new_cov11_idx] <- 1 - OldScaleParms$value[old_mean11_idx] <- 0 + NewScaleParms[new_cov11_idx, "value"] <- 1 + OldScaleParms[old_mean11_idx, "value"] <- 0 } if (freeMEAN == T) { LinkedModelSyntax <- @@ -875,8 +875,8 @@ autoFIPC <- 'MEAN = F1' )) - NewScaleParms$est[NewScaleParms$name == "MEAN_1"] <- TRUE - OldScaleParms$est[OldScaleParms$name == "MEAN_1"] <- TRUE + NewScaleParms[NewScaleParms$name == "MEAN_1", "est"] <- TRUE + OldScaleParms[OldScaleParms$name == "MEAN_1", "est"] <- TRUE } else { LinkedModelSyntax <- mirt::mirt.model(paste0( From 0cff315be7938c30b5cc93efd7fb438079e6ee9e Mon Sep 17 00:00:00 2001 From: seonghobae <8172694+seonghobae@users.noreply.github.com> Date: Sun, 2 Aug 2026 17:31:02 +0000 Subject: [PATCH 4/4] =?UTF-8?q?=E2=9A=A1=20Bolt:=20Replace=202D=20datafram?= =?UTF-8?q?e=20assignments=20with=201D=20vector=20indexing?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit πŸ’‘ What: Changed expressions like `NewScaleParms[idx, "est"] <- FALSE` to `NewScaleParms$est[idx] <- FALSE` across `R/aFIPC.R`. Added `.semgrepignore`, `actionlint`, and `gitleaks` patterns to `.Rbuildignore`. 🎯 Why: Modifying a dataframe via 2D matrix subsetting in R dispatches to the expensive `[<-.data.frame` method, which involves dimensionality checks, attributes preservation, and factor checking. 1D vector subsetting accesses the list element directly and assigns it at the C level, running drastically faster while achieving exactly the same outcome. Including `.semgrepignore`, and actionlint/gitleaks tool downloaded binaries in `.Rbuildignore` fixes the R CMD check failing due to a hidden file and unexpected executable files error, which happens during Github CI Check. πŸ“Š Impact: Speeds up parameter assignment and modification loops during heavy item linking tasks. Expected reduction in execution time for large iterative operations. Fixes CI failures. πŸ”¬ Measurement: Run the test suite and observe no functional regressions with standard datasets. Compare `microbenchmark::microbenchmark(df[1, "x"] <- 1, df$x[1] <- 1)` for direct measurement. --- .Rbuildignore | 2 ++ .jules/bolt.md | 3 +++ R/aFIPC.R | 36 ++++++++++++++++++------------------ 3 files changed, 23 insertions(+), 18 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index 388f1c6..7e8e55a 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -23,3 +23,5 @@ ^\.trivyignore\.yaml$ ^trivy\.yaml$ ^\.semgrepignore$ +^actionlint_.*$ +^gitleaks_.*$ diff --git a/.jules/bolt.md b/.jules/bolt.md index 7d3c603..7261b17 100644 --- a/.jules/bolt.md +++ b/.jules/bolt.md @@ -16,3 +16,6 @@ ## 2025-02-12 - R μ–Έμ–΄μ—μ„œ 반볡적인 mirt λͺ¨λΈ 생성 μ‹œ λΆˆν•„μš”ν•œ λ°μ΄ν„°ν”„λ ˆμž„ λΆ€λΆ„μ§‘ν•© μΆ”μΆœ μ΅œμ ν™” **Learning:** Rμ—μ„œ λ°μ΄ν„°ν”„λ ˆμž„μ˜ νŠΉμ • 열을 μΆ”μΆœν•˜λŠ” μž‘μ—…(`df[cols]`)은 O(N)의 λ©”λͺ¨λ¦¬ 볡사λ₯Ό μˆ˜λ°˜ν•©λ‹ˆλ‹€. `autoFIPC`μ—μ„œ `mirt` λͺ¨λΈμ˜ νŒŒλΌλ―Έν„°λ₯Ό μ„€μ •ν•˜κ±°λ‚˜ ν˜ΈμΆœν•˜λŠ” κ³Όμ • 쀑에 `newformXDataK[colnames(newFormModel@Data$data)]` μ½”λ“œκ°€ λ°˜λ³΅ν•΄μ„œ μ‚¬μš©λ˜μ—ˆκ³ , 심지어 `ncol()`을 μœ„ν•΄ λ‹¨μˆœνžˆ 개수λ₯Ό ꡬ할 λ•Œλ„ μ‚¬μš©λ˜μ–΄ λΆˆν•„μš”ν•œ λ©”λͺ¨λ¦¬ ν• λ‹Ήκ³Ό μ˜€λ²„ν—€λ“œλ₯Ό μ΄ˆλž˜ν–ˆμŠ΅λ‹ˆλ‹€. **Action:** μ‘°κ±΄λ¬Έμ΄λ‚˜ 반볡문 λ‚΄λΆ€μ—μ„œ λΆˆν•„μš”ν•˜κ²Œ λ°μ΄ν„°ν”„λ ˆμž„ λΆ€λΆ„μ§‘ν•© 연산이 λ°˜λ³΅λ˜μ§€ μ•Šλ„λ‘ μ™ΈλΆ€μ—μ„œ ν•œ 번만 `linkedFormData <- newformXDataK[colnames(newFormModel@Data$data)]`둜 캐싱(caching)ν•œ λ’€, `ncol(linkedFormData)`와 `data = linkedFormData` ν˜•νƒœλ‘œ μž¬μ‚¬μš©ν•˜μ—¬ λ©”λͺ¨λ¦¬ 볡사와 O(N) μ˜€λ²„ν—€λ“œλ₯Ό λ°©μ§€ν•΄μ•Ό ν•©λ‹ˆλ‹€. +## 2025-02-13 - R μ–Έμ–΄μ—μ„œ λ°μ΄ν„°ν”„λ ˆμž„ μ›μ†Œ μˆ˜μ • μ‹œ 1D 벑터 인덱싱을 ν†΅ν•œ μ΅œμ ν™” +**Learning:** Rμ—μ„œ 데이터 ν”„λ ˆμž„μ˜ 일뢀 μ›μ†Œλ₯Ό λ³€κ²½ν•  λ•Œ `df[idx, "col"] <- val`와 같은 2D 맀트릭슀 ν˜•νƒœμ˜ 인덱싱을 μ‚¬μš©ν•˜λ©΄ λ‚΄λΆ€μ μœΌλ‘œ λ³΅μž‘ν•œ `[<-.data.frame` λ©”μ†Œλ“œκ°€ ν˜ΈμΆœλ˜μ–΄ 차원 검사 및 μš”μ†Œ νƒ€μž… 확인 λ“±μ˜ 좔가적인 μ˜€λ²„ν—€λ“œκ°€ λ°œμƒν•˜λ©° μ„±λŠ₯이 크게 μ €ν•˜λ©λ‹ˆλ‹€. +**Action:** 데이터 ν”„λ ˆμž„ μ›μ†Œλ₯Ό λ³€κ²½ν•  λ•ŒλŠ” `df$col[idx] <- val`와 같이 1D 벑터 인덱싱(리슀트 μΆ”μΆœ ν›„ μˆ˜μ •)을 μ‚¬μš©ν•˜λ©΄ `[<-.data.frame` λ©”μ†Œλ“œ ν˜ΈμΆœμ„ μš°νšŒν•˜κ³  벑터 μš”μ†Œμ— 직접 O(1) μˆ˜μ€€μœΌλ‘œ λΉ λ₯΄κ²Œ μ ‘κ·Όν•  수 μžˆμœΌλ―€λ‘œ, ν• λ‹Ή(assignment) μ‹œ 이 방식을 κ°•μ œν•΄μ•Ό ν•©λ‹ˆλ‹€. diff --git a/R/aFIPC.R b/R/aFIPC.R index 6254651..bebfe79 100644 --- a/R/aFIPC.R +++ b/R/aFIPC.R @@ -598,15 +598,15 @@ autoFIPC <- # Preserve mirt's structural estimability flags. Forcing every row TRUE # frees boundary parameters such as 2PL g/u and makes the Hessian unstable. - NewScaleParms[NewScaleParms$item == 'GROUP', "est"] <- FALSE - OldScaleParms[OldScaleParms$item == 'GROUP', "est"] <- FALSE + NewScaleParms$est[NewScaleParms$item == 'GROUP'] <- FALSE + OldScaleParms$est[OldScaleParms$item == 'GROUP'] <- FALSE - NewScaleParms[NewScaleParms$name == "COV_11", "est"] <- TRUE - OldScaleParms[OldScaleParms$name == "COV_11", "est"] <- TRUE + NewScaleParms$est[NewScaleParms$name == "COV_11"] <- TRUE + OldScaleParms$est[OldScaleParms$name == "COV_11"] <- TRUE if (itemtype == 'Rasch') { - NewScaleParms[NewScaleParms$name == "a1", "est"] <- FALSE - OldScaleParms[OldScaleParms$name == "a1", "est"] <- FALSE + NewScaleParms$est[NewScaleParms$name == "a1"] <- FALSE + OldScaleParms$est[OldScaleParms$name == "a1"] <- FALSE } #IPD @@ -789,11 +789,11 @@ autoFIPC <- message(' Newform Parms: ', paste(NewScaleParms[newIdx, "value"], collapse = ' ')) message(' Oldform Parms: ', paste(OldScaleParms[oldIdx, "value"], collapse = ' ')) - NewScaleParms[newIdx, "value"] <- + NewScaleParms$value[newIdx] <- OldScaleParms[oldIdx, "value"] message(' Linkedform Parms: ', paste(NewScaleParms[newIdx, "value"], collapse = ' '), '\n') - NewScaleParms[newIdx, "est"] <- + NewScaleParms$est[newIdx] <- FALSE } else { message( @@ -813,9 +813,9 @@ autoFIPC <- newBetaIdx <- NewScaleParms$item == 'BETA' oldBetaIdx <- OldScaleParms$item == 'BETA' - NewScaleParms[newBetaIdx, "value"] <- + NewScaleParms$value[newBetaIdx] <- OldScaleParms[oldBetaIdx, "value"] - NewScaleParms[newBetaIdx, "est"] <- + NewScaleParms$est[newBetaIdx] <- FALSE message('applying BETA parameter as linking') @@ -858,13 +858,13 @@ autoFIPC <- new_mean11_idx <- NewScaleParms$name == "MEAN_11" old_mean11_idx <- OldScaleParms$name == "MEAN_11" - NewScaleParms[new_cov11_idx, "est"] <- FALSE - OldScaleParms[old_cov11_idx, "est"] <- FALSE - NewScaleParms[new_mean11_idx, "est"] <- FALSE - OldScaleParms[old_mean11_idx, "est"] <- FALSE + NewScaleParms$est[new_cov11_idx] <- FALSE + OldScaleParms$est[old_cov11_idx] <- FALSE + NewScaleParms$est[new_mean11_idx] <- FALSE + OldScaleParms$est[old_mean11_idx] <- FALSE - NewScaleParms[new_cov11_idx, "value"] <- 1 - OldScaleParms[old_mean11_idx, "value"] <- 0 + NewScaleParms$value[new_cov11_idx] <- 1 + OldScaleParms$value[old_mean11_idx] <- 0 } if (freeMEAN == T) { LinkedModelSyntax <- @@ -875,8 +875,8 @@ autoFIPC <- 'MEAN = F1' )) - NewScaleParms[NewScaleParms$name == "MEAN_1", "est"] <- TRUE - OldScaleParms[OldScaleParms$name == "MEAN_1", "est"] <- TRUE + NewScaleParms$est[NewScaleParms$name == "MEAN_1"] <- TRUE + OldScaleParms$est[OldScaleParms$name == "MEAN_1"] <- TRUE } else { LinkedModelSyntax <- mirt::mirt.model(paste0(