Nothing
# ==============================================================================
# Additional tests for lap_solve functions to increase coverage
# ==============================================================================
# ------------------------------------------------------------------------------
# assignment() input validation
# ------------------------------------------------------------------------------
test_that("assignment errors on empty matrix", {
expect_error(
assignment(matrix(nrow = 0, ncol = 0)),
"at least one row"
)
expect_error(
assignment(matrix(nrow = 0, ncol = 5)),
"at least one row"
)
expect_error(
assignment(matrix(nrow = 5, ncol = 0)),
"at least one row"
)
})
test_that("assignment errors on non-numeric matrix", {
expect_error(
assignment(matrix(c("a", "b", "c", "d"), 2, 2)),
"must be a numeric"
)
})
test_that("assignment errors on NaN values", {
cost <- matrix(c(1, NaN, 3, 4), 2, 2)
expect_error(
assignment(cost),
"NaN not allowed"
)
})
test_that("assignment handles eps parameter (deprecated)", {
cost <- matrix(c(1, 5, 5, 1), 2, 2)
# eps should be treated as auction_eps
result <- assignment(cost, method = "auction", eps = 0.001)
expect_equal(result$method_used, "auction")
})
# ------------------------------------------------------------------------------
# assignment() auto method selection
# ------------------------------------------------------------------------------
test_that("assignment auto selects bruteforce for n <= 8", {
cost <- matrix(runif(64), 8, 8)
result <- assignment(cost, method = "auto")
expect_equal(result$method_used, "bruteforce")
})
test_that("assignment auto selects hk01 for binary costs", {
# Need n > 8 for hk01 to be selected over bruteforce
cost <- matrix(sample(0:1, 100, replace = TRUE), 10, 10)
result <- assignment(cost, method = "auto")
expect_equal(result$method_used, "hk01")
})
test_that("assignment auto selects hk01 for constant costs", {
cost <- matrix(5, 10, 10)
result <- assignment(cost, method = "auto")
expect_equal(result$method_used, "hk01")
})
test_that("assignment auto selects lapmod for sparse matrices", {
set.seed(123)
n <- 150
cost <- matrix(NA, n, n)
# Fill only 30% of entries
idx <- sample(n * n, n * n * 0.3)
cost[idx] <- runif(length(idx), 1, 100)
result <- assignment(cost, method = "auto")
expect_equal(result$method_used, "lapmod")
})
test_that("assignment auto selects sap for very rectangular matrices", {
cost <- matrix(runif(30), 10, 30) # 10 rows, 30 cols (ratio = 3)
result <- assignment(cost, method = "auto")
expect_equal(result$method_used, "sap")
})
test_that("assignment auto selects hungarian for small-medium n", {
cost <- matrix(runif(40 * 40), 40, 40)
result <- assignment(cost, method = "auto")
expect_equal(result$method_used, "hungarian")
})
test_that("assignment auto selects jv for medium n", {
cost <- matrix(runif(60 * 60), 60, 60)
result <- assignment(cost, method = "auto")
expect_equal(result$method_used, "jv")
})
test_that("assignment auto selects auction_scaled for large n", {
cost <- matrix(runif(100 * 100), 100, 100)
result <- assignment(cost, method = "auto")
expect_equal(result$method_used, "auction_scaled")
})
# ------------------------------------------------------------------------------
# assignment() transpose handling
# ------------------------------------------------------------------------------
test_that("assignment handles rows > cols by transposing", {
cost <- matrix(runif(15), 5, 3) # 5 rows, 3 cols
result <- assignment(cost, method = "jv")
# After transpose, match length equals the smaller dimension
# But actually the function returns matches for original dimensions
expect_true(length(result$match) %in% c(3, 5))
})
# ------------------------------------------------------------------------------
# lap_solve() tests
# ------------------------------------------------------------------------------
test_that("lap_solve handles grouped data frames", {
df <- tibble::tibble(
sim = rep(1:2, each = 4),
source = rep(1:2, times = 4),
target = rep(1:2, each = 2, times = 2),
cost = c(1, 2, 3, 4, 5, 6, 7, 8)
)
result <- df |>
dplyr::group_by(sim) |>
lap_solve(source, target, cost)
expect_true("sim" %in% names(result))
})
test_that("lap_solve errors when data frame missing columns", {
df <- data.frame(a = 1:3, b = 4:6, c = 7:9)
expect_error(
lap_solve(df),
"must specify"
)
})
test_that("lap_solve handles matrix with some forbidden entries", {
# Create matrix with some NA entries
cost <- matrix(c(1, NA, 3, 4), 2, 2)
result <- lap_solve(cost)
expect_s3_class(result, "lap_solve_result")
})
test_that("lap_solve handles method parameter", {
cost <- matrix(c(1, 2, 3, 4), 2, 2)
result_auto <- lap_solve(cost, method = "auto")
result_hung <- lap_solve(cost, method = "hungarian")
expect_s3_class(result_auto, "lap_solve_result")
expect_s3_class(result_hung, "lap_solve_result")
})
test_that("lap_solve handles maximize parameter", {
cost <- matrix(c(1, 10, 10, 1), 2, 2)
result_min <- lap_solve(cost, maximize = FALSE)
result_max <- lap_solve(cost, maximize = TRUE)
expect_true(attr(result_max, "total_cost") > attr(result_min, "total_cost"))
})
# ------------------------------------------------------------------------------
# print.lap_solve_result tests
# ------------------------------------------------------------------------------
test_that("print.lap_solve_result handles tibble result", {
cost <- matrix(c(1, 2, 3, 4), 2, 2)
result <- lap_solve(cost)
output <- capture.output(print(result))
expect_true(any(grepl("Assignment Result", output)))
expect_true(any(grepl("Total cost", output)))
})
test_that("print.lap_solve_result handles list result", {
cost <- matrix(c(1, 2, 3, 4), 2, 2)
result <- assignment(cost)
output <- capture.output(print(result))
expect_true(any(grepl("Assignment", output)))
})
test_that("print.lap_solve_result handles many assignments", {
cost <- matrix(runif(144), 12, 12)
result <- assignment(cost, method = "hungarian")
output <- capture.output(print(result))
expect_true(any(grepl("more", output))) # Should show "... and X more"
})
test_that("print.lap_solve_result handles no assignments", {
# Force empty result
result <- tibble::tibble(
source = integer(0),
target = integer(0),
cost = numeric(0)
)
attr(result, "total_cost") <- 0
attr(result, "method_used") <- "test"
class(result) <- c("lap_solve_result", class(result))
output <- capture.output(print(result))
expect_true(any(grepl("Assignment", output)))
})
# ------------------------------------------------------------------------------
# lap_solve_line_metric tests
# ------------------------------------------------------------------------------
test_that("lap_solve_line_metric errors on empty x", {
expect_error(
lap_solve_line_metric(numeric(0), c(1, 2, 3)),
"non-empty"
)
})
test_that("lap_solve_line_metric errors on empty y", {
expect_error(
lap_solve_line_metric(c(1, 2, 3), numeric(0)),
"non-empty"
)
})
test_that("lap_solve_line_metric errors when x longer than y", {
expect_error(
lap_solve_line_metric(c(1, 2, 3), c(1, 2)),
"must be <="
)
})
test_that("lap_solve_line_metric errors on non-finite x", {
expect_error(
lap_solve_line_metric(c(1, NA, 3), c(1, 2, 3)),
"finite values"
)
expect_error(
lap_solve_line_metric(c(1, Inf, 3), c(1, 2, 3)),
"finite values"
)
})
test_that("lap_solve_line_metric errors on non-finite y", {
expect_error(
lap_solve_line_metric(c(1, 2, 3), c(1, NA, 3)),
"finite values"
)
})
test_that("lap_solve_line_metric errors on invalid cost", {
expect_error(
lap_solve_line_metric(c(1, 2), c(1, 2), cost = "invalid"),
"must be one of"
)
})
test_that("lap_solve_line_metric works with L1 cost", {
x <- c(1, 2, 3)
y <- c(1.5, 2.5, 3.5)
result <- lap_solve_line_metric(x, y, cost = "L1")
expect_equal(length(result$match), 3)
})
test_that("lap_solve_line_metric works with L2 cost", {
x <- c(1, 2, 3)
y <- c(1.5, 2.5, 3.5)
result <- lap_solve_line_metric(x, y, cost = "L2")
expect_equal(length(result$match), 3)
})
test_that("lap_solve_line_metric works with aliases", {
x <- c(1, 2, 3)
y <- c(1, 2, 3)
result_abs <- lap_solve_line_metric(x, y, cost = "abs")
result_manhattan <- lap_solve_line_metric(x, y, cost = "manhattan")
result_sq <- lap_solve_line_metric(x, y, cost = "sq")
result_squared <- lap_solve_line_metric(x, y, cost = "squared")
result_quadratic <- lap_solve_line_metric(x, y, cost = "quadratic")
expect_equal(length(result_abs$match), 3)
expect_equal(length(result_manhattan$match), 3)
expect_equal(length(result_sq$match), 3)
expect_equal(length(result_squared$match), 3)
expect_equal(length(result_quadratic$match), 3)
})
test_that("lap_solve_line_metric handles rectangular case", {
x <- c(1, 2, 3)
y <- c(1, 2, 3, 4, 5)
result <- lap_solve_line_metric(x, y)
expect_equal(length(result$match), 3)
})
test_that("print.lap_line_metric_result works", {
x <- c(1, 2, 3)
y <- c(1, 2, 3)
result <- lap_solve_line_metric(x, y)
output <- capture.output(print(result))
expect_true(any(grepl("Line Assignment", output)))
})
test_that("print.lap_line_metric_result handles many assignments", {
x <- 1:15
y <- 1:15
result <- lap_solve_line_metric(x, y)
output <- capture.output(print(result))
expect_true(any(grepl("more", output)))
})
# ------------------------------------------------------------------------------
# bottleneck_assignment tests
# ------------------------------------------------------------------------------
test_that("bottleneck_assignment errors on empty matrix", {
expect_error(
bottleneck_assignment(matrix(nrow = 0, ncol = 0)),
"at least one"
)
})
test_that("bottleneck_assignment errors on non-numeric", {
expect_error(
bottleneck_assignment(matrix(c("a", "b", "c", "d"), 2, 2)),
"must be a numeric"
)
})
test_that("bottleneck_assignment errors on NaN", {
expect_error(
bottleneck_assignment(matrix(c(1, NaN, 3, 4), 2, 2)),
"NaN not allowed"
)
})
test_that("bottleneck_assignment errors on rows > cols", {
expect_error(
bottleneck_assignment(matrix(runif(6), 3, 2)),
"nrow <= ncol"
)
})
test_that("bottleneck_assignment minimizes max edge", {
cost <- matrix(c(1, 5, 3, 2, 4, 6, 7, 1, 2), 3, 3, byrow = TRUE)
result <- bottleneck_assignment(cost)
expect_s3_class(result, "bottleneck_result")
# The bottleneck value should be optimal
expect_true(result$bottleneck >= 0)
})
test_that("bottleneck_assignment maximize works", {
cost <- matrix(c(10, 5, 8, 6, 12, 4, 3, 7, 11), 3, 3, byrow = TRUE)
result <- bottleneck_assignment(cost, maximize = TRUE)
expect_s3_class(result, "bottleneck_result")
})
test_that("print.bottleneck_result works", {
cost <- matrix(c(1, 2, 3, 4), 2, 2)
result <- bottleneck_assignment(cost)
output <- capture.output(print(result))
expect_true(any(grepl("Bottleneck", output)))
})
test_that("print.bottleneck_result handles many assignments", {
cost <- matrix(runif(144), 12, 12)
result <- bottleneck_assignment(cost)
output <- capture.output(print(result))
expect_true(any(grepl("more", output)))
})
# ------------------------------------------------------------------------------
# assignment_duals tests
# ------------------------------------------------------------------------------
test_that("assignment_duals errors on empty matrix", {
# Use numeric() to ensure empty matrix is numeric type
expect_error(
assignment_duals(matrix(numeric(0), nrow = 0, ncol = 0)),
"at least one row and one column"
)
})
test_that("assignment_duals errors on non-numeric", {
expect_error(
assignment_duals(matrix(c("a", "b", "c", "d"), 2, 2)),
"must be a numeric"
)
})
test_that("assignment_duals errors on NaN", {
expect_error(
assignment_duals(matrix(c(1, NaN, 3, 4), 2, 2)),
"NaN not allowed"
)
})
test_that("assignment_duals returns duals that satisfy complementary slackness", {
cost <- matrix(c(4, 2, 5, 3, 3, 6, 7, 5, 4), 3, 3, byrow = TRUE)
result <- assignment_duals(cost)
expect_s3_class(result, "assignment_duals_result")
expect_equal(length(result$u), 3)
expect_equal(length(result$v), 3)
# Check complementary slackness for assigned pairs
for (i in seq_len(3)) {
j <- result$match[i]
if (j > 0) {
expect_equal(result$u[i] + result$v[j], cost[i, j], tolerance = 1e-6)
}
}
})
test_that("assignment_duals handles maximize", {
cost <- matrix(c(1, 10, 10, 1), 2, 2)
result <- assignment_duals(cost, maximize = TRUE)
expect_s3_class(result, "assignment_duals_result")
})
test_that("assignment_duals handles transpose", {
cost <- matrix(runif(15), 5, 3) # More rows than cols (5x3)
result <- assignment_duals(cost)
# After transpose handling, dimensions match original matrix:
# match has length = nrow(cost) = 5
# u has length = nrow(cost) = 5
# v has length = ncol(cost) = 3
expect_equal(length(result$match), 5)
expect_equal(length(result$u), 5)
expect_equal(length(result$v), 3)
})
test_that("print.assignment_duals_result works", {
cost <- matrix(c(1, 2, 3, 4), 2, 2)
result <- assignment_duals(cost)
output <- capture.output(print(result))
expect_true(any(grepl("Dual", output)))
})
test_that("print.assignment_duals_result handles many assignments", {
cost <- matrix(runif(144), 12, 12)
result <- assignment_duals(cost)
output <- capture.output(print(result))
expect_true(any(grepl("more", output)))
})
# ------------------------------------------------------------------------------
# sinkhorn tests
# ------------------------------------------------------------------------------
test_that("sinkhorn errors on non-matrix input", {
expect_error(
sinkhorn("not a matrix"),
"must be a numeric"
)
})
test_that("sinkhorn errors on non-positive lambda", {
expect_error(
sinkhorn(matrix(1:4, 2, 2), lambda = 0),
"must be positive"
)
expect_error(
sinkhorn(matrix(1:4, 2, 2), lambda = -1),
"must be positive"
)
})
test_that("sinkhorn_to_assignment errors on invalid input", {
expect_error(
sinkhorn_to_assignment("not valid"),
"must be"
)
})
test_that("sinkhorn_to_assignment accepts matrix directly", {
P <- matrix(c(0.8, 0.2, 0.2, 0.8), 2, 2)
result <- sinkhorn_to_assignment(P)
expect_equal(length(result), 2)
})
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.