Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# prego 0.0.10

* Fix: `calc_seq_pwm()` / `extract_pwm()` now error clearly when given sequences
of unequal length instead of silently recycling the shorter ones (via `rbind`)
and returning wrong scores. These functions build a single rectangular one-hot
matrix and require equal-length sequences; for variable lengths use
`compute_pwm()`.
* Fix: PWM scoring no longer opens thousands of threads / fails on core-limited
machines. `compute_pwm()`, `compute_local_pwm()` and `calc_seq_pwm()` (hence
`extract_pwm()`) run a small per-sequence BLAS `dgemm` inside an
Expand Down
7 changes: 7 additions & 0 deletions R/pwm.R
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ calc_seq_pwm <- function(sequences, mdb, bidirect = TRUE) {
stop("sequences must be a character vector")
}

# calc_seq_pwm builds a single rectangular one-hot matrix, so all sequences
# must be the same length. Unequal lengths would silently recycle the shorter
# rows (via rbind) and return wrong scores - fail loudly instead.
if (length(unique(nchar(sequences))) > 1) {
cli_abort("All {.field sequences} must have the same length for {.fn extract_pwm}. For sequences of different lengths, use {.fn compute_pwm}.")
}

# Convert sequences to uppercase and save original names
sequences <- toupper(sequences)
seq_names <- names(sequences)
Expand Down
16 changes: 16 additions & 0 deletions tests/testthat/test-pwm.R
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,22 @@ test_that("compute_pwm and calc_seq_pwm produce the same results", {
expect_true(abs(scores_new - scores_old) < 1e-6)
})

test_that("calc_seq_pwm errors on sequences of unequal length", {
test_motif_db <- data.frame(
motif = "test_motif", pos = 1:4,
A = c(0.7, 0.1, 0.1, 0.1), C = c(0.1, 0.7, 0.1, 0.1),
G = c(0.1, 0.1, 0.7, 0.1), T = c(0.1, 0.1, 0.1, 0.7)
)
test_mdb <- create_motif_db(test_motif_db)
# Unequal lengths used to silently recycle (rbind) and return wrong scores.
expect_error(
calc_seq_pwm(c("ACGTACGT", "ACGTAC"), test_mdb),
"same length"
)
# Equal lengths still work.
expect_silent(calc_seq_pwm(c("ACGTACGT", "TGCATGCA"), test_mdb))
})

test_that("compute_pwm and calc_seq_pwm produce the same results with spatial", {
res <- regress_pwm(cluster_sequences_example, cluster_mat_example[, 1],
final_metric = "ks", spat_bin_size = 40,
Expand Down
Loading