test_that("author_weights returns correct values for all 13 methods", { ## 3 authors n <- 3 ## Fractional: equal share w <- author_weights(n, "fractional") expect_equal(w, c(1/3, 1/3, 1/3), tolerance = tol) expect_equal(sum(w), 1, tolerance = tol) ## Harmonic: (1/1, 1/2, 1/3) / H_3 w <- author_weights(n, "harmonic") h3 <- 1 + 1/2 + 1/3 expect_equal(w, c(1/h3, (1/2)/h3, (1/3)/h3), tolerance = tol) expect_equal(sum(w), 1, tolerance = tol) ## Arithmetic: (3, 2, 1) / 6 w <- author_weights(n, "arithmetic") expect_equal(w, c(3/6, 2/6, 1/6), tolerance = tol) ## Geometric: (0.25, 0.5, 1) normalized... wait (0.5^0, 0.5^1, 0.5^2) = (1, 0.5, 0.25) w <- author_weights(n, "geometric") raw <- c(1, 0.5, 0.25) expect_equal(w, raw / sum(raw), tolerance = tol) ## Adaptive geometric: ratio first/last = 3 w <- author_weights(n, "adaptive_geometric") expect_equal(w[1] / w[3], 3, tolerance = 0.01) expect_equal(sum(w), 1, tolerance = tol) ## Golden: phi-based w <- author_weights(n, "golden") phi <- (1 + sqrt(5)) / 2 raw <- c(phi^2, phi^1, phi^0) expect_equal(w, raw / sum(raw), tolerance = tol) ## First author only w <- author_weights(n, "first") expect_equal(w, c(1, 0, 0)) ## Last author only w <- author_weights(n, "last") expect_equal(w, c(0, 0, 1)) ## First-last elevated w <- author_weights(n, "first_last") expect_true(w[1] == w[3]) # first == last expect_true(w[1] > w[2]) # elevated > middle expect_equal(sum(w), 1, tolerance = tol) ## Position weighted w <- author_weights(n, "position_weighted") expect_equal(sum(w), 1, tolerance = tol) ## Full: all ones (NOT normalized to 1) w <- author_weights(n, "full") expect_equal(w, c(1, 1, 1)) }) test_that("author_weights handles single author", { for (m in all_counts()) { w <- author_weights(1, m) expect_equal(w, 1) } }) test_that("all position-dependent methods sum to 1", { for (n in 2:10) { for (m in position_dependent_counts()) { w <- author_weights(n, m) expect_equal(sum(w), 1, tolerance = tol, info = sprintf("%s with n=%d", m, n)) } } }) test_that("harmonic matches crisstats formula", { ## From crisstats: weight_i = (1/position) / sum(1/1:n) for (n in c(2, 5, 10)) { w <- author_weights(n, "harmonic") h_n <- sum(1 / seq_len(n)) expected <- (1 / seq_len(n)) / h_n expect_equal(w, expected, tolerance = tol) } }) test_that("geometric matches crisstats formula", { ## From crisstats: weight_i = 0.5^(i-1), normalized for (n in c(2, 5, 10)) { w <- author_weights(n, "geometric") raw <- 0.5^(seq_len(n) - 1) expected <- raw / sum(raw) expect_equal(w, expected, tolerance = tol) } }) test_that("build_author_bipartite produces correct positional weights", { d <- make_test_data() ## Harmonic weighting B <- build_author_bipartite(d, counting = "harmonic") ## W1 has Alice (pos 1) and Bob (pos 2), n=2 ## Harmonic: H_2 = 1 + 0.5 = 1.5 ## Alice: (1/1)/1.5 = 2/3, Bob: (1/2)/1.5 = 1/3 expect_equal(B["W1", "ALICE"], 2/3, tolerance = tol) expect_equal(B["W1", "BOB"], 1/3, tolerance = tol) ## W3 has Bob (pos 1), Carol (pos 2), Dan (pos 3), n=3 h3 <- 1 + 1/2 + 1/3 expect_equal(B["W3", "BOB"], 1/h3, tolerance = tol) expect_equal(B["W3", "CAROL"], (1/2)/h3, tolerance = tol) expect_equal(B["W3", "DAN"], (1/3)/h3, tolerance = tol) })