Nothing
# ==============================================================================
# Tests for eigen_indices.R — Chapter 7 Eigen Selection Index Methods
#
# Functions covered: esim(), resim(), ppg_esim()
# Helpers tested indirectly: .esim_solve_sym_multi(), .eigen_index_metrics(),
# .leading_eigenvector()
# ==============================================================================
# ------------------------------------------------------------------------------
# Shared fixtures (2-trait synthetic + real seldata matrices)
# ------------------------------------------------------------------------------
# Small 2×2 system with known spectral properties:
# P^{-1}G = [5 1; 1 4] [10 2; 2 8]^{-1} — exact eigenvalues computable by hand
P_2 <- matrix(c(10, 2, 2, 8), nrow = 2)
G_2 <- matrix(c(5, 1, 1, 4), nrow = 2)
# 3×3 system used for restriction tests
P_3 <- matrix(c(
10, 2, 1,
2, 8, 1,
1, 1, 6
), nrow = 3, byrow = TRUE)
G_3 <- matrix(c(
5, 1, 0.5,
1, 4, 0.5,
0.5, 0.5, 3
), nrow = 3, byrow = TRUE)
colnames(P_3) <- colnames(G_3) <- c("T1", "T2", "T3")
# ==============================================================================
# ===== ESIM =================================================================
# ==============================================================================
test_that("esim: output structure is correct", {
r <- esim(P_2, G_2)
expect_s3_class(r, "esim")
expect_s3_class(r, "eigen_index")
expected_names <- c(
"summary", "b", "Delta_G", "sigma_I",
"hI2", "rHI", "lambda2", "implied_w",
"all_eigenvalues", "selection_intensity",
"trait_names", "pmat", "gmat"
)
expect_true(all(expected_names %in% names(r)))
# summary is a data frame
expect_s3_class(r$summary, "data.frame")
expect_equal(nrow(r$summary), 1L) # default n_indices = 1
# b and Delta_G are numeric vectors of correct length
expect_true(is.numeric(r$b))
expect_false(is.matrix(r$b))
expect_equal(length(r$b), 2L)
expect_equal(length(r$Delta_G), 2L)
# scalar outputs are single finite numbers
for (field in c("sigma_I", "hI2", "rHI", "lambda2")) {
expect_true(is.numeric(r[[field]]) && length(r[[field]]) == 1L,
label = paste("scalar:", field)
)
expect_true(is.finite(r[[field]]), label = paste("finite:", field))
}
})
test_that("esim: leading eigenvalue equals index heritability", {
r <- esim(P_2, G_2)
# The leading eigenvalue of P^{-1}G IS h^2_I by definition
P_inv_G <- solve(P_2) %*% G_2
ev <- eigen(P_inv_G)
lambda2_ref <- max(Re(ev$values))
expect_equal(r$lambda2, lambda2_ref, tolerance = 1e-6)
expect_equal(r$hI2, lambda2_ref, tolerance = 1e-6)
expect_equal(r$rHI, sqrt(lambda2_ref), tolerance = 1e-6)
})
test_that("esim: b_E is the eigenvector of P^{-1}G for the leading eigenvalue", {
r <- esim(P_2, G_2)
P_inv_G <- solve(P_2) %*% G_2
# (P^{-1}G) b = lambda^2 b => residual P^{-1}G b - lambda^2 b ≈ 0
residual <- as.numeric(P_inv_G %*% r$b - r$lambda2 * r$b)
expect_true(all(abs(residual) < 1e-8),
label = "b_E satisfies (P^{-1}G - lambda^2 I) b = 0"
)
})
test_that("esim: metric formulas are internally consistent", {
r <- esim(P_3, G_3)
b <- as.numeric(r$b)
# sigma_I = sqrt(b'Pb)
bPb <- as.numeric(t(b) %*% P_3 %*% b)
expect_equal(r$sigma_I, sqrt(bPb), tolerance = 1e-8)
# hI2 = b'Gb / b'Pb (also == lambda2)
bGb <- as.numeric(t(b) %*% G_3 %*% b)
expect_equal(r$hI2, bGb / bPb, tolerance = 1e-8)
expect_equal(r$rHI, sqrt(r$hI2), tolerance = 1e-8)
k_I <- r$selection_intensity
expect_equal(r$summary$Delta_G[1], k_I * r$sigma_I, tolerance = 1e-6)
# Delta_G vector = (k_I / sigma_I) * G b
DG_expected <- as.numeric(k_I * (G_3 %*% b) / r$sigma_I)
expect_equal(as.numeric(r$Delta_G), DG_expected, tolerance = 1e-8)
})
test_that("esim: n_indices > 1 returns multiple rows in summary", {
r <- esim(P_3, G_3, n_indices = 3L)
# P_3 is 3×3, so at most 3 positive eigenvalues
expect_true(nrow(r$summary) >= 1L)
expect_true(nrow(r$summary) <= 3L)
# Eigenvalues in summary should be in descending order
lambdas <- r$summary$lambda2
expect_true(all(diff(lambdas) <= 0 + 1e-10))
})
test_that("esim: returns correct trait names from column names", {
r <- esim(P_3, G_3)
expect_equal(r$trait_names, c("T1", "T2", "T3"))
expect_equal(names(r$b), c("T1", "T2", "T3"))
expect_equal(names(r$Delta_G), c("T1", "T2", "T3"))
})
test_that("esim: fallback trait names when matrices have no colnames", {
P_nc <- P_2
colnames(P_nc) <- NULL
G_nc <- G_2
colnames(G_nc) <- NULL
r <- esim(P_nc, G_nc)
expect_equal(r$trait_names, c("Trait_1", "Trait_2"))
})
test_that("esim: input validation catches bad inputs", {
skip_on_cran() # error handling test or warning test
expect_error(esim(P_2, G_3), regexp = "same dimensions")
expect_error(esim(matrix(1), matrix(1)), regexp = "At least 2 traits")
non_sym <- P_2
non_sym[1, 2] <- 999
expect_error(esim(non_sym, G_2), regexp = "symmetric")
})
test_that("esim: works on real seldata matrices", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
gmat <- gen_varcov(seldata[, 3:9], seldata[, 2], seldata[, 1])
pmat <- phen_varcov(seldata[, 3:9], seldata[, 2], seldata[, 1])
r <- esim(pmat, gmat)
expect_s3_class(r, "esim")
expect_equal(length(r$b), 7L)
expect_true(r$hI2 > 0 && r$hI2 < 1)
expect_true(r$rHI > 0 && r$rHI < 1)
expect_true(r$sigma_I > 0)
})
test_that("esim: print and summary return invisibly without error", {
r <- esim(P_3, G_3)
capture.output(expect_invisible(print(r)))
capture.output(expect_invisible(summary(r)))
})
test_that("esim: results are deterministic across repeated calls", {
r1 <- esim(P_3, G_3)
r2 <- esim(P_3, G_3)
expect_equal(r1$b, r2$b)
expect_equal(r1$lambda2, r2$lambda2)
expect_equal(r1$Delta_G, r2$Delta_G)
})
test_that("esim: custom selection_intensity scales sigma_I correctly", {
k1 <- 2.063
k2 <- 1.755 # 20 % selection
r1 <- esim(P_3, G_3, selection_intensity = k1)
r2 <- esim(P_3, G_3, selection_intensity = k2)
# b and lambda2 are independent of k_I (purely from eigenproblem)
expect_equal(r1$b, r2$b, tolerance = 1e-10)
expect_equal(r1$lambda2, r2$lambda2, tolerance = 1e-10)
# Delta_G (scalar) scales with k_I
expect_equal(r1$summary$Delta_G[1] / r2$summary$Delta_G[1], k1 / k2,
tolerance = 1e-6
)
})
# ==============================================================================
# ===== RESIM ================================================================
# ==============================================================================
test_that("resim: output structure is correct", {
r <- resim(P_3, G_3, restricted_traits = 1L)
expect_s3_class(r, "resim")
expect_s3_class(r, "eigen_index")
expected_names <- c(
"summary", "b", "Delta_G", "sigma_I",
"hI2", "rHI", "lambda2", "K", "Q_R",
"U_mat", "restricted_traits", "implied_w",
"selection_intensity", "trait_names", "pmat", "gmat"
)
expect_true(all(expected_names %in% names(r)))
expect_s3_class(r$summary, "data.frame")
expect_equal(nrow(r$summary), 1L)
expect_equal(length(r$b), 3L)
expect_equal(length(r$Delta_G), 3L)
for (field in c("sigma_I", "hI2", "rHI", "lambda2")) {
expect_true(is.finite(r[[field]]), label = paste("finite:", field))
}
})
test_that("resim: single restricted trait has near-zero genetic gain", {
skip_on_cran() # Numerical precision depends on BLAS/LAPACK implementation
r <- resim(P_3, G_3, restricted_traits = 1L)
expect_true(abs(r$Delta_G["T1"]) < 1e-6,
label = "Restricted trait T1 has Delta_G ≈ 0"
)
})
test_that("resim: two restricted traits both have near-zero gain", {
skip_on_cran() # Numerical precision depends on BLAS/LAPACK implementation
r <- resim(P_3, G_3, restricted_traits = c(1L, 2L))
expect_true(abs(r$Delta_G["T1"]) < 1e-6)
expect_true(abs(r$Delta_G["T2"]) < 1e-6)
})
test_that("resim: unrestricted traits are free to respond", {
r <- resim(P_3, G_3, restricted_traits = 1L)
# T2 and T3 are unrestricted — their gains should generally be non-zero
expect_true(abs(r$Delta_G["T2"]) > 1e-8 || abs(r$Delta_G["T3"]) > 1e-8)
})
test_that("resim: restriction satisfied via formula U' G b ≈ 0", {
skip_on_cran() # Numerical precision depends on BLAS/LAPACK implementation
r <- resim(P_3, G_3, restricted_traits = c(1L, 3L))
U <- r$U_mat
b <- as.numeric(r$b)
# The formal RESIM constraint is U' C b = 0 (C = gmat)
constraint <- as.numeric(t(U) %*% G_3 %*% b)
expect_true(all(abs(constraint) < 1e-6),
label = "U' G b = 0 for all restricted traits"
)
})
test_that("resim: accepts custom U_mat and matches restricted_traits version", {
r1 <- resim(P_3, G_3, restricted_traits = c(1L, 2L))
U <- diag(3)[, c(1L, 2L), drop = FALSE]
r2 <- resim(P_3, G_3, U_mat = U)
expect_equal(r1$b, r2$b, tolerance = 1e-8)
expect_equal(r1$lambda2, r2$lambda2, tolerance = 1e-8)
})
test_that("resim: K is a projection matrix (K^2 = K)", {
r <- resim(P_3, G_3, restricted_traits = 1L)
K <- r$K
expect_equal(K %*% K, K, tolerance = 1e-8)
})
test_that("resim: lambda2 < esim lambda2 (restriction reduces heritability)", {
re <- esim(P_3, G_3)
rr <- resim(P_3, G_3, restricted_traits = 1L)
expect_true(rr$lambda2 <= re$lambda2 + 1e-10,
label = "Restriction cannot improve maximum index heritability"
)
})
test_that("resim: input validation catches bad inputs", {
skip_on_cran() # error handling test or warning test
expect_error(resim(P_3, G_3),
regexp = "restricted_traits.*U_mat"
)
expect_error(resim(P_3, G_3, restricted_traits = c(1L, 2L, 3L)),
regexp = "less than number of traits"
)
expect_error(resim(P_3, G_3, restricted_traits = 5L),
regexp = "valid trait indices"
)
})
test_that("resim: works on real seldata matrices", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
gmat <- gen_varcov(seldata[, 3:9], seldata[, 2], seldata[, 1])
pmat <- phen_varcov(seldata[, 3:9], seldata[, 2], seldata[, 1])
r <- resim(pmat, gmat, restricted_traits = c(1L, 3L))
expect_s3_class(r, "resim")
expect_true(abs(r$Delta_G[1]) < 1e-6) # trait 1 restricted
expect_true(abs(r$Delta_G[3]) < 1e-6) # trait 3 restricted
})
test_that("resim: print and summary return invisibly without error", {
r <- resim(P_3, G_3, restricted_traits = 1L)
capture.output(expect_invisible(print(r)))
capture.output(expect_invisible(summary(r)))
})
# ==============================================================================
# ===== PPG-ESIM =============================================================
# ==============================================================================
test_that("ppg_esim: output structure is correct", {
d <- c(1, 1)
r <- ppg_esim(P_2, G_2, d)
expect_s3_class(r, "ppg_esim")
expect_s3_class(r, "eigen_index")
expected_names <- c(
"summary", "beta", "b", "Delta_G", "sigma_I",
"hI2", "rHI", "lambda2", "F_mat", "K_P",
"Q_P", "D_M", "desired_gains",
"selection_intensity", "trait_names", "pmat", "gmat"
)
expect_true(all(expected_names %in% names(r)))
expect_s3_class(r$summary, "data.frame")
expect_equal(length(r$beta), 2L)
expect_equal(length(r$b), 2L)
expect_equal(length(r$Delta_G), 2L)
for (field in c("sigma_I", "hI2", "rHI", "lambda2")) {
expect_true(is.finite(r[[field]]), label = paste("finite:", field))
}
})
test_that("ppg_esim: Mallard matrix D_M is orthogonal to d", {
d <- c(2, 1, -1)
r <- ppg_esim(P_3, G_3, d)
d_unit <- d / sqrt(sum(d^2))
# Every column of D_M must be orthogonal to d_unit
inner_products <- as.numeric(t(r$D_M) %*% d_unit)
expect_true(all(abs(inner_products) < 1e-10),
label = "D_M columns are orthogonal to d"
)
# D_M columns should be orthonormal among themselves
DtD <- t(r$D_M) %*% r$D_M
expect_equal(DtD, diag(ncol(r$D_M)), tolerance = 1e-10)
})
test_that("ppg_esim: K_P is a rank-1 projection matrix", {
d <- c(1, 2, 1)
r <- ppg_esim(P_3, G_3, d)
K <- r$K_P
expect_equal(K %*% K, K, tolerance = 1e-8)
# Rank 1: K_P is an oblique projection (not symmetric), so eigen() may return
# complex values on some platforms; use Re() to discard numerical-noise imaginary parts.
rank_K <- sum(Re(eigen(K, only.values = TRUE)$values) > 0.5)
expect_equal(rank_K, 1L)
})
test_that("ppg_esim: gains are exactly proportional to d (equal d)", {
d <- rep(1, 3)
r <- ppg_esim(P_3, G_3, d)
dg <- as.numeric(r$Delta_G)
ratios <- dg / d
cv <- sd(ratios) / abs(mean(ratios))
expect_true(cv < 1e-8,
label = paste("CV of gain ratios:", cv)
)
})
test_that("ppg_esim: gains are exactly proportional to d (asymmetric d)", {
d <- c(3, 1, 2)
r <- ppg_esim(P_3, G_3, d)
dg <- as.numeric(r$Delta_G)
ratios <- dg / d
cv <- sd(ratios) / abs(mean(ratios))
expect_true(cv < 1e-8,
label = paste("CV of gain ratios:", cv)
)
})
test_that("ppg_esim: gains are exactly proportional to d (mixed sign d)", {
d <- c(1, -1, 1)
r <- ppg_esim(P_3, G_3, d)
dg <- as.numeric(r$Delta_G)
ratios <- dg / d
cv <- sd(ratios) / abs(mean(ratios))
expect_true(cv < 1e-8,
label = paste("CV of gain ratios:", cv)
)
})
test_that("ppg_esim: gains are exactly proportional on real seldata (7 traits)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
gmat <- gen_varcov(seldata[, 3:9], seldata[, 2], seldata[, 1])
pmat <- phen_varcov(seldata[, 3:9], seldata[, 2], seldata[, 1])
for (dtest in list(rep(1, 7), c(2, 1, 1, 1, 1, 1, 1), c(1, 1, -1, 1, -1, 1, 1))) {
r <- ppg_esim(pmat, gmat, dtest)
dg <- as.numeric(r$Delta_G)
ratios <- dg / dtest
cv <- sd(ratios) / abs(mean(ratios))
expect_true(cv < 1e-6,
label = paste("CV:", cv, "for d:", paste(dtest, collapse = ","))
)
}
})
test_that("ppg_esim: phi (mean ratio) is positive — gains align with d", {
d1 <- c(1, 1, 1)
d2 <- c(2, 1, -1)
for (d in list(d1, d2)) {
r <- ppg_esim(P_3, G_3, d)
dg <- as.numeric(r$Delta_G)
phi <- mean(dg / d)
expect_true(phi > 0,
label = paste("phi > 0 for d:", paste(d, collapse = ","))
)
}
})
test_that("ppg_esim: beta = F b and F is scalar ±I", {
d <- c(1, 2, 1)
r <- ppg_esim(P_3, G_3, d)
beta_reconstructed <- as.numeric(r$F_mat %*% r$b)
expect_equal(as.numeric(r$beta), beta_reconstructed, tolerance = 1e-10)
# F_mat must be a scalar multiple of identity (±I)
diag_vals <- diag(r$F_mat)
expect_true(length(unique(diag_vals)) == 1L,
label = "F_mat is scalar ±I"
)
expect_true(abs(abs(diag_vals[1]) - 1) < 1e-10,
label = "diagonal of F_mat is ±1"
)
# Off-diagonal elements are zero
off_diag <- r$F_mat - diag(diag_vals)
expect_true(all(abs(off_diag) < 1e-10))
})
test_that("ppg_esim: metric formulas are internally consistent", {
d <- c(2, 1, 1)
r <- ppg_esim(P_3, G_3, d)
beta <- as.numeric(r$beta)
bPb <- as.numeric(t(beta) %*% P_3 %*% beta)
bGb <- as.numeric(t(beta) %*% G_3 %*% beta)
k_I <- r$selection_intensity
expect_equal(r$sigma_I, sqrt(bPb), tolerance = 1e-8)
expect_equal(r$hI2, bGb / bPb, tolerance = 1e-8)
expect_equal(r$rHI, sqrt(r$hI2), tolerance = 1e-8)
DG_expected <- as.numeric(k_I * (G_3 %*% beta) / r$sigma_I)
expect_equal(as.numeric(r$Delta_G), DG_expected, tolerance = 1e-8)
})
test_that("ppg_esim: D_M has correct dimensions (t x t-1)", {
d <- c(1, 2, 3)
r <- ppg_esim(P_3, G_3, d)
expect_equal(dim(r$D_M), c(3L, 2L))
})
test_that("ppg_esim: scaling d does not change the gain direction", {
d1 <- c(1, 2, 1)
d2 <- d1 * 5 # scaled version
r1 <- ppg_esim(P_3, G_3, d1)
r2 <- ppg_esim(P_3, G_3, d2)
# Gains should be proportional (same direction, possibly different scale)
ratio1 <- as.numeric(r1$Delta_G) / as.numeric(r2$Delta_G)
cv <- sd(ratio1) / abs(mean(ratio1))
expect_true(cv < 1e-8,
label = "Scaling d does not change the gain ratio pattern"
)
})
test_that("ppg_esim: lambda2 <= esim lambda2 (PPG constraint reduces heritability)", {
d <- c(2, 1, 1)
re <- esim(P_3, G_3)
rp <- ppg_esim(P_3, G_3, d)
expect_true(rp$lambda2 <= re$lambda2 + 1e-10,
label = "PPG constraint cannot improve free-optimum heritability"
)
})
test_that("ppg_esim: input validation catches bad inputs", {
skip_on_cran() # error handling test or warning test
expect_error(ppg_esim(P_3, G_3, c(1, 1)),
regexp = "same length"
)
expect_error(ppg_esim(P_3, G_3, c(0, 0, 0)),
regexp = "non-zero"
)
non_sym <- P_3
non_sym[1, 2] <- 999
expect_error(ppg_esim(non_sym, G_3, c(1, 1, 1)),
regexp = "symmetric"
)
})
test_that("ppg_esim: print and summary return invisibly without error", {
d <- c(2, 1, 1)
r <- ppg_esim(P_3, G_3, d)
capture.output(expect_invisible(print(r)))
capture.output(expect_invisible(summary(r)))
})
test_that("ppg_esim: results are deterministic across repeated calls", {
d <- c(1, 2, 1)
r1 <- ppg_esim(P_3, G_3, d)
r2 <- ppg_esim(P_3, G_3, d)
expect_equal(r1$beta, r2$beta)
expect_equal(r1$lambda2, r2$lambda2)
expect_equal(r1$Delta_G, r2$Delta_G)
})
# ==============================================================================
# ===== Cross-method consistency =============================================
# ==============================================================================
test_that("esim >= resim >= ppg_esim in heritability (hierarchy of constraints)", {
skip_on_cran() # heavy cross-products / TRE regex — bypass CRAN sanitizers
gmat <- gen_varcov(seldata[, 3:9], seldata[, 2], seldata[, 1])
pmat <- phen_varcov(seldata[, 3:9], seldata[, 2], seldata[, 1])
re <- esim(pmat, gmat)
rr <- resim(pmat, gmat, restricted_traits = 1L)
rp <- ppg_esim(pmat, gmat, rep(1, 7))
# Free ESIM achieves the maximum; restrictions can only reduce it
expect_true(re$lambda2 >= rr$lambda2 - 1e-8)
expect_true(re$lambda2 >= rp$lambda2 - 1e-8)
})
test_that("esim without restrictions equals resim with zero restrictions (edge case)", {
skip_on_cran() # error handling test or warning test
# RESIM with restriction on 0 traits is ill-formed — verify proper error
# (not a valid call — at least 1 restriction required)
expect_error(resim(P_3, G_3, restricted_traits = integer(0)),
regexp = "restricted_traits"
)
})
# ==============================================================================
# NEW COVERAGE TESTS — targeting previously uncovered lines
# ==============================================================================
# Helper: small valid 2x2 matrices with known properties
.P2 <- matrix(c(10, 2, 2, 8), nrow = 2)
.G2 <- matrix(c(5, 1, 1, 4), nrow = 2)
# --- .eigen_index_metrics: line 87 – Delta_G_vec = rep(NA, nrow(G)) --------
# Triggered when bPb <= 0 (sigma_I is NA), so the Delta_G vector branch
# at line 84 goes to the else: rep(NA_real_, nrow(G)).
test_that(".eigen_index_metrics returns NA Delta_G_vec when bPb <= 0 (line 87)", {
# Build b perpendicular to P's positive-definite direction by giving a
# degenerate b = 0 so b'Pb = 0.
b_zero <- c(0, 0)
m <- selection.index:::.eigen_index_metrics(b_zero, .P2, .G2, lambda2 = NULL)
expect_true(all(is.na(m$Delta_G_vec)))
expect_equal(length(m$Delta_G_vec), nrow(.G2))
})
# --- .eigen_index_metrics: line 94 – bGb/bPb fallback when lambda2=NULL ---
# When lambda2 is NULL and bPb > 0 (valid b), hI2 = bGb/bPb (line 94).
test_that(".eigen_index_metrics uses bGb/bPb when lambda2=NULL (line 94)", {
# Use a non-zero b for meaningful bPb
b <- c(1, 0)
m <- selection.index:::.eigen_index_metrics(b, .P2, .G2, lambda2 = NULL)
# bPb = b'Pb = [1,0] [10,2;2,8] [1,0]' = 10
# bGb = b'Gb = [1,0] [5,1;1,4] [1,0]' = 5
expect_equal(m$hI2, 5 / 10, tolerance = 1e-10)
expect_equal(m$hI2, m$bGb / m$bPb, tolerance = 1e-10)
})
# --- .leading_eigenvector: lines 133-134 – no positive eigenvalues ----------
# Supply a negative-definite matrix (negated identity) so all eigenvalues <= 0.
test_that(".leading_eigenvector stops when no positive eigenvalues (lines 133-134)", {
skip_on_cran() # error handling test or warning test
neg_mat <- -diag(3) # all eigenvalues = -1 <= 0
expect_error(
selection.index:::.leading_eigenvector(neg_mat),
"No positive eigenvalues found"
)
})
# --- esim: line 228 – non-symmetric gmat -----------------------------------
test_that("esim errors on non-symmetric gmat (line 228)", {
skip_on_cran() # error handling test or warning test
bad_g <- .G2
bad_g[1, 2] <- 999
expect_error(esim(.P2, bad_g), regexp = "symmetric")
})
# --- esim: lines 280-281 – implied_w tryCatch fallback ----------------------
# Mock ginv in selection.index namespace to throw; implied_w tryCatch catches
# and returns rep(NA_real_, n_traits) + emits a warning.
test_that("esim implied_w tryCatch returns NA and warns when ginv fails (lines 280-281)", {
expect_warning(
{
r <- with_mocked_bindings(
ginv = function(...) stop("mocked ginv failure"),
.package = "selection.index",
esim(.P2, .G2)
)
},
"Could not compute implied economic weights"
)
expect_true(all(is.na(r$implied_w)))
expect_equal(length(r$implied_w), 2L)
})
# --- resim: line 423 – non-symmetric pmat ----------------------------------
test_that("resim errors on non-symmetric pmat (line 423)", {
skip_on_cran() # error handling test or warning test
bad_p <- P_3
bad_p[1, 2] <- 999
expect_error(resim(bad_p, G_3, restricted_traits = 1L),
regexp = "pmat must be a symmetric matrix"
)
})
# --- resim: line 425 – non-symmetric gmat ----------------------------------
test_that("resim errors on non-symmetric gmat (line 425)", {
skip_on_cran() # error handling test or warning test
bad_g <- G_3
bad_g[1, 2] <- 999
expect_error(resim(P_3, bad_g, restricted_traits = 1L),
regexp = "gmat must be a symmetric matrix"
)
})
# --- resim: line 427 – dimension mismatch (nrow(pmat) != nrow(gmat)) -------
test_that("resim errors when pmat and gmat have different dims (line 427)", {
skip_on_cran() # error handling test or warning test
expect_error(
resim(P_3, .G2, restricted_traits = 1L),
regexp = "same dimensions"
)
})
# --- resim: line 431 – auto-generate trait names when no colnames ----------
test_that("resim auto-generates trait names when pmat has no colnames (line 431)", {
P_nc <- P_3
colnames(P_nc) <- NULL
G_nc <- G_3
colnames(G_nc) <- NULL
r <- resim(P_nc, G_nc, restricted_traits = 1L)
expect_equal(r$trait_names, paste0("Trait_", 1:3))
})
# --- resim: line 447 – U_mat with wrong nrow --------------------------------
test_that("resim errors when U_mat nrow != n_traits (line 447)", {
skip_on_cran() # error handling test or warning test
U_wrong <- matrix(c(1, 0), nrow = 2, ncol = 1) # nrow=2 but n_traits=3
expect_error(
resim(P_3, G_3, U_mat = U_wrong),
regexp = "U_mat must have nrow equal to n_traits"
)
})
# --- resim: lines 498-499 – implied_w tryCatch fallback -------------------
# resim calls ginv() once in its own computation (mid_inv, line 467) and once
# inside the implied_w tryCatch (G_inv, line 495). A stateful counter mock
# lets the first call succeed and fails only the second, so we reach line 498-499.
test_that("resim implied_w tryCatch returns NA and warns when ginv fails (lines 498-499)", {
call_count <- 0L
real_ginv <- MASS::ginv
r <- NULL
expect_warning(
{
r <- with_mocked_bindings(
ginv = function(X, ...) {
call_count <<- call_count + 1L
if (call_count < 2L) real_ginv(X, ...) else stop("mocked ginv failure")
},
.package = "selection.index",
resim(P_3, G_3, restricted_traits = 1L)
)
},
"Could not compute implied weights"
)
expect_true(all(is.na(r$implied_w)))
expect_equal(length(r$implied_w), nrow(P_3))
})
# --- ppg_esim: line 653 – non-symmetric gmat --------------------------------
test_that("ppg_esim errors on non-symmetric gmat (line 653)", {
skip_on_cran() # error handling test or warning test
bad_g <- G_3
bad_g[1, 2] <- 999
expect_error(ppg_esim(P_3, bad_g, d = c(1, 1, 1)),
regexp = "symmetric"
)
})
# --- ppg_esim: line 655 – dimension mismatch --------------------------------
test_that("ppg_esim errors when pmat and gmat have different dims (line 655)", {
skip_on_cran() # error handling test or warning test
expect_error(
ppg_esim(P_3, .G2, d = c(1, 1, 1)),
regexp = "same dimensions"
)
})
# --- ppg_esim: lines 699-701 – solve(mid) fails, falls back to ginv --------
# With G_zero (all-zero), Psi_DM = 0, so mid = 0 -> solve(0) fails and the
# warning at line 699-700 fires. The function then continues with ginv(0) = 0,
# leading to K_P = I, then v_norm < 1e-12 -> stop at line 728-729.
# Wrap in tryCatch to swallow the downstream stop so we can verify the warning.
test_that("ppg_esim warning when middle matrix is singular, falls back to ginv (lines 699-701)", {
G_zero <- matrix(0, 3, 3) # Psi_DM = G*D_M = 0 -> mid = 0 -> solve fails
# The function emits the singularity warning first, then stops due to v_norm=0.
# Capture the warning before the subsequent error propagates.
expect_warning(
tryCatch(
ppg_esim(P_3, G_zero, d = c(1, 0.01, 0.01)),
error = function(e) NULL # swallow downstream v_norm stop
),
"Middle matrix in Q_P is singular"
)
})
# --- ppg_esim: lines 728-729 – v_norm < 1e-12 → stop -----------------------
# When P_inv_G = 0 (G=0) and K_P * 0 = 0, v_raw = 0 → v_norm = 0 → stop.
# Actually with G=0, K_P * P^{-1}*G * d_unit = K_P * 0 = 0, so v_norm < 1e-12.
# This test requires ginv fallback path. After ginv of a zero mid gives 0 K_P,
# then v_raw = K_P * P^{-1}*0 * d = 0, so v_norm = 0.
test_that("ppg_esim stops when v_norm is numerically zero (lines 728-729)", {
skip_on_cran() # error handling test or warning test
G_zero <- matrix(0, 3, 3) # makes P^{-1}G = 0, so K_P*(P^{-1}G)*d = 0
expect_error(
suppressWarnings(
ppg_esim(P_3, G_zero, d = c(1, 1, 1))
),
"K_P.*P.*{-1}G.*d is numerically zero|numerically zero"
)
})
# --- ppg_esim: line 749 – sign_corr == 0 → sign_corr <- 1L -----------------
# sign_corr = sign(sum(tentative_gain * d)) = 0 when G*b_P is perpendicular to d.
# With an all-zero G, G*b_P = 0, so sum(0 * d) = 0 → sign_corr = 0 → line 749.
# We need G that makes G*b_P orthogonal to d but still has P^{-1}G != 0.
# Construct G_skew: symmetric, with G*b ⊥ d for the specific b that arises.
# Easier: use a G where G*b_P happens to be exactly orthogonal to d.
# This is very hard to engineer analytically. Instead, mock the internal
# tentative_gain calculation by providing a custom G where the gain is
# numerically zero — same approach as G_zero above, but bypass the v_norm stop.
# We can achieve line 749 by using a G that is not zero (so v_norm > 0) but
# produces G*b_P exactly orthogonal to d. Since b_P ∝ K_P * P^{-1}G * d,
# and gmat*b_P ≡ 0 iff G*b_P = 0, we need G to map b_P to zero.
# The simplest synthetic case: G singular with null space containing b_P.
# For the 2-trait system, d = c(1,1): if G * b_P = 0 and b_P ≠ 0:
# pick G = outer(c(-1,1), c(1,1)) (rank 1, maps b_P to 0 if b_P ∝ c(1,1))
# Let's verify: b_P = K_P * P^{-1}G * d/||d||. With G = [-1 -1; 1 1], K_P at
# rank 1 projects onto d=c(1,1) direction, b_P ∝ c(1,1).
# G * c(1,1) = c(-2, 2) ≠ 0, so this doesn't work directly.
# Use G = c(1,-1)c(1,1)': G * c(1,-1) = c(1-1, -1+1) = 0 after normalization.
# This is very hard to guarantee analytically, so use the mock-based approach.
test_that("ppg_esim handles sign_corr = 0 by defaulting to 1 (line 749)", {
# It is mathematically impossible for G*b_P = 0 AND v_norm > 0 in exact arithmetic.
# We mock the internal solver to decouple the two checks.
P_test <- diag(2)
G_test <- matrix(c(0, 0, 0, 1), 2, 2)
d_test <- c(1, 0)
mock_solve <- function(pmat, mat) {
if (ncol(mat) == nrow(pmat)) {
# For P_inv_G calculation, return Identity so v_raw = K_P * I * d = c(1,0) -> v_norm = 1
diag(2)
} else {
# For P_inv_PsiDM calculation, return normal matrix multiplication
mat
}
}
testthat::with_mocked_bindings(
.esim_solve_sym_multi = mock_solve,
.package = "selection.index",
code = {
# This forces b_P = c(1, 0).
# Then tentative_gain = G_test %*% c(1, 0) = c(0, 0).
# sum(c(0,0) * d_test) == 0, triggering the fallback.
expect_no_error(
res <- ppg_esim(P_test, G_test, d = d_test)
)
expect_equal(as.numeric(res$b), c(1, 0), tolerance = 1e-5)
}
)
})
# --- print.resim: line 954 – rep(FALSE, ...) when restricted_traits is NULL --
# When resim is called with U_mat (not restricted_traits), result$restricted_traits
# is NULL. The print method at line 951-954 hits the else: rep(FALSE, ...).
test_that("print.resim reaches rep(FALSE,...) when restricted_traits is NULL (line 954)", {
U_mat <- diag(3)[, 1L, drop = FALSE] # U_mat provided, not restricted_traits
r <- resim(P_3, G_3, U_mat = U_mat)
expect_null(r$restricted_traits)
# Print should run without error and reach the else branch at line 954
out <- capture.output(print(r))
# The Restricted column should be present and all FALSE
expect_true(any(grepl("Restricted", out, fixed = TRUE)) || is.character(out))
})
# --- print.ppg_esim: lines 1062-1066 – high CV → "[!]" branch ---------------
# The "[OK]" branch at line 1059 requires cv_ratio < 0.02.
# The "[!]" branch at line 1062 fires when cv_ratio >= 0.02.
# We can force this by constructing a result object with inconsistent
# desired_gains and Delta_G (high CV of ratios).
test_that("print.ppg_esim prints '[!]' message when CV >= 0.02 (lines 1062-1066)", {
# Build a minimal valid ppg_esim result with manually forced high CV ratios.
r <- ppg_esim(P_3, G_3, d = c(1, 1, 1))
# Manually overwrite desired_gains to create high CV:
# ratios = Delta_G / d; if d is very non-uniform and Delta_G is uniform,
# CV will be high.
r$desired_gains <- c(0.001, 1000, 0.001) # wildly non-proportional to Delta_G
out <- capture.output(print(r))
expect_true(any(grepl("[!]", out, fixed = TRUE)),
info = "Expected '[!]' line in print output when CV >= 0.02"
)
})
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.