## Tests for community_detect(), simulate_sbm(), simulate_dcsbm(), ## misclustering_rate(), and core internal functions. # ---- simulate_sbm ----------------------------------------------------------- test_that("simulate_sbm returns correct structure", { B <- matrix(c(0.3, 0.05, 0.05, 0.3), 2, 2) sim <- simulate_sbm(n = 100, K = 2, B = B, seed = 1) expect_s3_class(sim, "sbm_sim") expect_equal(sim$n, 100) expect_equal(sim$K, 2) expect_equal(nrow(sim$A), 100) expect_equal(ncol(sim$A), 100) expect_equal(length(sim$labels), 100) expect_true(all(sim$labels %in% 1:2)) # Adjacency matrix is symmetric expect_equal(sim$A, Matrix::t(sim$A)) # No self-loops expect_equal(sum(Matrix::diag(sim$A)), 0) }) test_that("simulate_sbm is reproducible with seed", { B <- matrix(c(0.3, 0.05, 0.05, 0.3), 2, 2) sim1 <- simulate_sbm(n = 50, K = 2, B = B, seed = 99) sim2 <- simulate_sbm(n = 50, K = 2, B = B, seed = 99) expect_identical(sim1$labels, sim2$labels) expect_equal(sim1$A, sim2$A) }) # ---- simulate_dcsbm --------------------------------------------------------- test_that("simulate_dcsbm returns correct structure", { B <- matrix(c(0.4, 0.05, 0.05, 0.4), 2, 2) theta <- rep(1, 100) sim <- simulate_dcsbm(n = 100, K = 2, B = B, theta = theta, seed = 5) expect_s3_class(sim, "dcsbm_sim") expect_equal(sim$n, 100) expect_equal(length(sim$labels), 100) expect_equal(sim$A, Matrix::t(sim$A)) }) # ---- misclustering_rate ----------------------------------------------------- test_that("misclustering_rate is 0 for perfect recovery (up to permutation)", { true <- c(1, 1, 1, 2, 2, 2) est <- c(2, 2, 2, 1, 1, 1) # same partition, labels swapped expect_equal(misclustering_rate(true, est), 0) }) test_that("misclustering_rate is 1/2 for completely wrong two-community assignment", { true <- c(1, 1, 2, 2) est <- c(1, 2, 1, 2) # every node misclassified regardless of permutation # Best match assigns 2 correct out of 4 → rate = 0.5 expect_equal(misclustering_rate(true, est), 0.5) }) test_that("misclustering_rate errors on mismatched lengths", { expect_error(misclustering_rate(1:5, 1:4)) }) # ---- community_detect (SBM) ------------------------------------------------- test_that("community_detect with SBM recovers two communities at low noise", { # Well-separated two-community SBM B <- matrix(c(0.5, 0.02, 0.02, 0.5), 2, 2) sim <- simulate_sbm(n = 200, K = 2, B = B, seed = 42) fit <- community_detect(sim$A, K = 2, model = "sbm", n_init = 5, seed = 42) expect_s3_class(fit, "sparsecommunity") expect_equal(length(fit$labels), 200) expect_equal(fit$K, 2) expect_equal(fit$model, "sbm") expect_equal(dim(fit$embedding), c(200, 2)) expect_equal(length(fit$eigenvalues), 2) err <- misclustering_rate(sim$labels, fit$labels) expect_lt(err, 0.1) # expect < 10% misclustering }) # ---- community_detect (DCSBM) ----------------------------------------------- test_that("community_detect with DCSBM recovers communities with degree heterogeneity", { set.seed(7) B <- matrix(c(0.6, 0.03, 0.03, 0.6), 2, 2) theta <- runif(200, 0.5, 1.5) sim <- simulate_dcsbm(n = 200, K = 2, B = B, theta = theta, seed = 7) fit <- community_detect(sim$A, K = 2, model = "dcsbm", n_init = 5, seed = 7) expect_s3_class(fit, "sparsecommunity") expect_equal(fit$model, "dcsbm") # Embedding rows should be unit-normalized row_norms <- sqrt(rowSums(fit$embedding^2)) expect_true(all(abs(row_norms - 1) < 1e-6 | row_norms < 1e-6)) err <- misclustering_rate(sim$labels, fit$labels) expect_lt(err, 0.1) }) # ---- community_detect input validation -------------------------------------- test_that("community_detect errors on non-square matrix", { A <- matrix(0, 5, 4) expect_error(community_detect(A, K = 2), "square") }) test_that("community_detect errors on K < 2", { B <- matrix(c(0.3, 0.05, 0.05, 0.3), 2, 2) sim <- simulate_sbm(n = 50, K = 2, B = B, seed = 1) expect_error(community_detect(sim$A, K = 1), "K") })