Nothing
# Backend-agnostic regression tests for facility location solvers.
#
# These pin known-good objective values from the Rust backend (captured
# April 2026) and assert structural invariants that any correct backend
# must satisfy. Exact facility selections are NOT pinned because
# tie-breaking may differ across backends.
#
# Tolerances vary by solver: 1e-1 for p_median/mclp, 1e-2 for
# p_center/p_dispersion, ~1 for cflp. Loose enough to survive
# backend changes, tight enough to catch model formulation errors.
skip_if_not_installed("sf")
library(sf)
# ---------------------------------------------------------------------------
# Shared fixture helper
# ---------------------------------------------------------------------------
make_solver_data <- function(n_demand, n_fac, seed = 123) {
set.seed(seed)
demand <- st_as_sf(
data.frame(
x = runif(n_demand, 0, 10),
y = runif(n_demand, 0, 10),
pop = rpois(n_demand, 50) + 1L
),
coords = c("x", "y")
)
facilities <- st_as_sf(
data.frame(
x = runif(n_fac, 0, 10),
y = runif(n_fac, 0, 10)
),
coords = c("x", "y")
)
list(demand = demand, facilities = facilities)
}
# ---------------------------------------------------------------------------
# P-Median
# Pinned: objective = 3498.296111
# ---------------------------------------------------------------------------
test_that("p_median: pinned objective and invariants", {
d <- make_solver_data(30, 10, seed = 101)
result <- p_median(d$demand, d$facilities, n_facilities = 3, weight_col = "pop")
meta <- attr(result, "spopt")
# Pinned objective
expect_equal(meta$objective, 3498.296, tolerance = 1e-1)
# Structural invariants
expect_equal(meta$n_selected, 3)
expect_equal(sum(result$facilities$.selected), 3)
expect_true(all(result$demand$.facility %in% which(result$facilities$.selected)))
expect_equal(nrow(result$demand), 30)
expect_true(meta$mean_distance > 0)
})
# ---------------------------------------------------------------------------
# LSCP
# Pinned: objective = 2, n_selected = 2, coverage_pct = 100
# ---------------------------------------------------------------------------
test_that("lscp: pinned objective and coverage", {
d <- make_solver_data(20, 8, seed = 202)
result <- lscp(d$demand, d$facilities, service_radius = 5.0)
meta <- attr(result, "spopt")
# Pinned values
expect_equal(meta$objective, 2)
expect_equal(meta$n_selected, 2)
expect_equal(meta$coverage_pct, 100)
expect_equal(meta$uncoverable_demand, 0)
# All demand should be covered
expect_true(all(result$demand$.covered))
})
# ---------------------------------------------------------------------------
# MCLP
# Pinned: objective = 1667, coverage_pct = 66.0
# ---------------------------------------------------------------------------
test_that("mclp: pinned objective and coverage", {
d <- make_solver_data(50, 10, seed = 303)
result <- mclp(d$demand, d$facilities, service_radius = 3.0,
n_facilities = 3, weight_col = "pop")
meta <- attr(result, "spopt")
# Pinned values
expect_equal(meta$objective, 1667, tolerance = 1e-1)
expect_equal(meta$n_selected, 3)
expect_equal(meta$coverage_pct, 66.0, tolerance = 0.5)
expect_equal(meta$covered_weight, 1667, tolerance = 1e-1)
expect_equal(meta$total_weight, 2527)
})
# ---------------------------------------------------------------------------
# P-Center (both methods)
# Pinned: max_distance = 4.555352 (both methods must agree)
# ---------------------------------------------------------------------------
test_that("p_center: pinned max_distance and method equivalence", {
d <- make_solver_data(30, 10, seed = 404)
result_bs <- p_center(d$demand, d$facilities, n_facilities = 3,
method = "binary_search")
result_mip <- p_center(d$demand, d$facilities, n_facilities = 3,
method = "mip")
meta_bs <- attr(result_bs, "spopt")
meta_mip <- attr(result_mip, "spopt")
# Pinned value
expect_equal(meta_bs$max_distance, 4.5554, tolerance = 1e-2)
# Method equivalence
expect_equal(meta_bs$max_distance, meta_mip$max_distance, tolerance = 1e-4)
# Structural invariants
expect_equal(meta_bs$n_selected, 3)
expect_equal(meta_mip$n_selected, 3)
expect_true(all(result_bs$demand$.facility %in% which(result_bs$facilities$.selected)))
expect_true(all(result_mip$demand$.facility %in% which(result_mip$facilities$.selected)))
# Verify max_distance is actually the max assignment distance
cost_mat <- as.matrix(sf::st_distance(d$demand, d$facilities))
assigned_dists_bs <- sapply(seq_len(nrow(d$demand)), function(i) {
cost_mat[i, result_bs$demand$.facility[i]]
})
expect_equal(max(assigned_dists_bs), meta_bs$max_distance, tolerance = 1e-4)
})
# ---------------------------------------------------------------------------
# P-Dispersion
# Pinned: min_distance = 5.336305
# ---------------------------------------------------------------------------
test_that("p_dispersion: pinned min_distance and pairwise invariant", {
set.seed(505)
fac <- st_as_sf(
data.frame(x = runif(15, 0, 10), y = runif(15, 0, 10)),
coords = c("x", "y")
)
result <- p_dispersion(fac, n_facilities = 4)
meta <- attr(result, "spopt")
# Pinned value
expect_equal(meta$min_distance, 5.3363, tolerance = 1e-2)
expect_equal(meta$n_selected, 4)
# Mathematical invariant: all pairwise distances >= min_distance
selected_idx <- which(result$.selected)
dist_mat <- as.matrix(sf::st_distance(result[selected_idx, ]))
pairwise <- dist_mat[upper.tri(dist_mat)]
expect_true(all(pairwise >= meta$min_distance - 1e-4))
})
# ---------------------------------------------------------------------------
# CFLP (fixed number of facilities)
# Pinned: objective = 4650.079, n_split = 0
# ---------------------------------------------------------------------------
test_that("cflp: pinned objective, allocation parity, and capacity invariants", {
d <- make_solver_data(40, 10, seed = 606)
cap_val <- max(sum(d$demand$pop) / 3, max(d$demand$pop))
d$facilities$cap <- rep(cap_val, 10)
result <- cflp(d$demand, d$facilities, n_facilities = 4,
weight_col = "pop", capacity_col = "cap")
meta <- attr(result, "spopt")
# Pinned values
expect_equal(meta$objective, 4650.08, tolerance = 1)
expect_equal(meta$n_selected, 4)
expect_equal(meta$n_split_demand, 0)
# Allocation matrix: must exist, correct dimensions, rows sum to 1
alloc <- meta$allocation_matrix
expect_true(!is.null(alloc))
expect_equal(nrow(alloc), 40)
expect_equal(ncol(alloc), 10)
expect_equal(as.numeric(rowSums(alloc)), rep(1.0, 40), tolerance = 1e-6)
# Allocation only to selected facilities
selected <- which(result$facilities$.selected)
non_selected <- setdiff(1:10, selected)
expect_true(all(alloc[, non_selected] < 1e-6))
# Capacity constraints: weighted allocation <= capacity for each selected facility
weights <- d$demand$pop
for (j in selected) {
allocated_weight <- sum(weights * alloc[, j])
expect_lte(allocated_weight, cap_val + 1e-6)
}
# Utilizations in [0, 1]
selected_fac <- result$facilities[result$facilities$.selected, ]
expect_true(all(selected_fac$.utilization >= -1e-6))
expect_true(all(selected_fac$.utilization <= 1 + 1e-6))
# Primary assignment consistent with allocation (only check rows
# where a single facility has dominant allocation > 0.99)
for (i in seq_len(40)) {
max_alloc <- max(alloc[i, ])
if (max_alloc > 0.99) {
primary <- result$demand$.facility[i]
expect_equal(primary, which.max(alloc[i, ]))
}
}
})
# ---------------------------------------------------------------------------
# CFLP (cost-based, no fixed n)
# Pinned: objective = 3409.637, n_selected = 7
# ---------------------------------------------------------------------------
test_that("cflp with facility costs: pinned objective and allocation", {
set.seed(707)
d <- make_solver_data(30, 8, seed = 707)
d$facilities$cap <- rep(sum(d$demand$pop), 8)
d$facilities$fcost <- runif(8, 10, 50)
result <- cflp(d$demand, d$facilities, n_facilities = 0,
weight_col = "pop", capacity_col = "cap",
facility_cost_col = "fcost")
meta <- attr(result, "spopt")
# Pinned values
expect_equal(meta$objective, 3409.64, tolerance = 1)
expect_equal(meta$n_selected, 7)
# Allocation rows sum to 1
alloc <- meta$allocation_matrix
expect_equal(as.numeric(rowSums(alloc)), rep(1.0, 30), tolerance = 1e-6)
# All demands assigned
expect_true(all(!is.na(result$demand$.facility)))
})
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.