tests/testthat/test-qqchisq1.R

test_that("qqchisq1 small-N path matches qqlog for equivalent inputs", {
  set.seed(123)
  chisq_vals <- stats::rchisq(500, df = 1)

  # Reference: convert in R then run qqlog logic
  log10_ref <- -stats::pchisq(chisq_vals, df = 1,
                               lower.tail = FALSE, log.p = TRUE) / log(10)
  log10_ref <- log10_ref[log10_ref > 0 & is.finite(log10_ref)]
  o_ref <- sort(log10_ref, decreasing = TRUE)
  e_ref <- -log10(stats::ppoints(length(o_ref)))

  # qqchisq1 small-N logic
  chisq_clean <- chisq_vals[chisq_vals >= 0]
  log10_chisq <- -stats::pchisq(chisq_clean, df = 1,
                                 lower.tail = FALSE, log.p = TRUE) / log(10)
  log10_chisq <- log10_chisq[log10_chisq > 0]
  o_chisq <- sort(log10_chisq, decreasing = TRUE)
  e_chisq <- -log10(stats::ppoints(length(o_chisq)))

  expect_equal(o_chisq, o_ref)
  expect_equal(e_chisq, e_ref)
})

test_that("drop_dense_chisq1 large-N path matches drop_dense_qqlog", {
  set.seed(123)
  chisq_vals <- stats::rchisq(5e4, df = 1)

  # Compute -log10(p) reference in R using same formula as C++
  log10_pvals <- -stats::pchisq(chisq_vals, df = 1,
                                 lower.tail = FALSE, log.p = TRUE) / log(10)

  res_chisq <- fastqq:::drop_dense_chisq1(chisq_vals, 10000L)
  res_qqlog  <- fastqq:::drop_dense_qqlog(log10_pvals, 10000L)

  expect_equal(res_chisq[[1]], res_qqlog[[1]], tolerance = 1e-10)
  expect_equal(res_chisq[[2]], res_qqlog[[2]], tolerance = 1e-10)
})

test_that("qqchisq1 handles extreme chi-sq values without underflow", {
  # For chisq = 1000, p is astronomically small; log-space prevents underflow
  extreme_vals <- c(1, 10, 100, 500, 1000)
  log10_p <- -stats::pchisq(extreme_vals, df = 1,
                              lower.tail = FALSE, log.p = TRUE) / log(10)
  expect_true(all(is.finite(log10_p)))
  expect_true(all(log10_p > 0))
  expect_true(log10_p[5] > log10_p[4])  # monotonically increasing
})

test_that("qqchisq1 correctly places a point with p < 1e-500 on the plot", {
  # chisq ~ 2303 gives p ~ 10^-500, far below .Machine$double.xmin (~2.2e-308).
  # Naive pchisq underflows to 0; qqchisq1 must not lose this point.
  extreme_chisq <- 2303

  # Confirm the naive approach gives 0 (underflow)
  expect_equal(stats::pchisq(extreme_chisq, 1, lower.tail = FALSE), 0)

  # Confirm log-space gives a finite -log10(p) near 500
  neg_log10_p <- -stats::pchisq(extreme_chisq, 1,
                                 lower.tail = FALSE, log.p = TRUE) / log(10)
  expect_true(is.finite(neg_log10_p))
  expect_gt(neg_log10_p, 490)   # should be close to 500
  expect_lt(neg_log10_p, 510)

  # Mix with typical chi-sq values and confirm the extreme point appears
  set.seed(42)
  chisq_vals <- c(stats::rchisq(500, df = 1), extreme_chisq)
  OEmat <- fastqq:::drop_dense_chisq1(chisq_vals, 10000L)
  observed <- OEmat[[1]]

  # The extreme point (max observed) should be near 500
  expect_gt(max(observed), 490)
  expect_lt(max(observed), 510)
})

Try the fastqq package in your browser

Any scripts or data that you put into this service are public.

fastqq documentation built on March 13, 2026, 9:08 a.m.