This vignette records how the package was checked: the routing solver
against public benchmark instances and other solvers, and the estimators by
simulation. The large runs were done once, outside the package build, with
the scripts of the fieldopt-core repository; the small ones run here.
Figure of the chunk unnamed-chunk-2
Instances with rounded Euclidean distances, as the libraries define them, one core of a laptop, one seed; "proven" means the certificate closed the gap within ten seconds:
| Set | Instances | Setting | Optimal | Mean gap | Largest gap | Time | |-----------------------|---:|---------------|-------------:|-------:|-------:|-----------:| | TSPLIB (51 to 101 nodes) | 7 | 2000 offspring | 7 of 7 (6 proven) | 0.00% | 0.00% | 0.7 to 4.7 s | | Augerat A (CVRP, 31 to 79 customers) | 27 | 200 offspring (default) | 14 of 27 | 0.20% | 1.14% | under 0.4 s | | Augerat A | 27 | 2000 offspring | 24 of 27 | 0.01% | 0.15% | 0.7 to 4 s | | Cordeau MDVRP (50 to 360 customers, 2 to 6 depots) | 23 | 2000 offspring | 11 of 23 at or below best known | 0.29% | 1.5% | 1 to 26 s | | Cordeau MDVRP | 23 | 20 s each | 13 of 23 at or below best known | 0.26% | 1.9% | 20 s |
Other solvers on the same instances: PyVRP through the vrpr package
reaches 18 of 27 Augerat optima in one second and 24 in five (mean gap
0.05%); HiGHS on the compact MTZ formulation solves the TSP up to 51 nodes
(21 s) but stays 40 to 60 percent away from the optimum after three
minutes on the smallest Augerat instances, which is why the package does
not route with a general MIP solver.
Stability: across eight seeds on four instances the gap moved by less than one percentage point (standard deviation below 0.3 points).
Internal checks in the engine's test suite: every local-search move is priced in constant time and was checked against a full recomputation on tens of thousands of accepted moves; the exact dynamic programme and the split of giant tours were checked against brute force on hundreds of random instances with one to three depots and asymmetric costs; the lower bounds never exceed the exact optimum; an independent review found and fixed four defects before release.
Small Monte Carlo checks, run here, of the unbiasedness of the main estimators.
set.seed(4) cells <- expand_grid(x = 1:15, y = 1:15) |> mutate(unit = paste0("c", row_number())) areas <- expand_grid(unit = cells$unit, k = 1:3) |> transmute(unit, establishment = paste0(unit, "-", k), area = 0.3, y = rlnorm(n(), 2, 0.5)) deff <- point_design_effect( cells, areas, n = 25, points_per_cell = 6, cell_size = 1, n_sim = 60, seed = 2 ) deff |> select(bias, variance, mean_variance_estimate, deff) #> # A tibble: 1 × 4 #> bias variance mean_variance_estimate deff #> <dbl> <dbl> <dbl> <dbl> #> 1 56.127 158401. 167223. 1.4716
set.seed(7) cells <- cells |> mutate( domain = if_else(runif(n()) < 0.2, "ab", "a"), yv = if_else(domain == "ab", 80, 10) + rnorm(n(), sd = 3) ) overlap <- cells |> filter(domain == "ab") lst <- bind_rows( overlap |> transmute(unit = paste0("l", row_number()), domain, yv), tibble(unit = paste0("b", 1:12), domain = "b", yv = 120 + rnorm(12, sd = 5)) ) |> mutate(x = runif(n()), y = runif(n())) truth <- sum(cells$yv) + sum(lst$yv[lst$domain == "b"]) est <- map(1:40, \(k) { sa <- cells |> select_units(n = 30, seed = k) sb <- lst |> select_units(n = 15, method = "srs", seed = k) tibble( hartley = dual_frame_estimator(sa, sb, "yv", "domain")$total, fb = dual_frame_estimator(sa, sb, "yv", "domain", estimator = "fuller-burmeister")$total ) }) |> list_rbind() est |> summarise(across(everything(), mean)) |> mutate(truth = truth, .before = 1) #> # A tibble: 1 × 3 #> truth hartley fb #> <dbl> <dbl> <dbl> #> 1 6182.1 6221.3 6247.1 # relative bias in percent est |> summarise(across(everything(), \(e) round(100 * (mean(e) - truth) / truth, 2))) #> # A tibble: 1 × 2 #> hartley fb #> <dbl> <dbl> #> 1 0.63 1.05
Further checks live in the test suite: the Hartley allocation against a
grid search over the mixing weight, Cochran's two-stage optimum against
enumeration, the multivariate allocation against an integer grid, the cube
method's balance against simple random sampling, and the survey designs
produced by as_svydesign() against the package's own totals and replicate
variances.
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.