|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| has_data_table <- function() {
|
|
|
| requireNamespace("data.table", quietly = TRUE)
|
| }
|
|
|
|
|
|
|
|
|
| has_parallel <- function() {
|
| requireNamespace("future", quietly = TRUE) &&
|
| requireNamespace("furrr", quietly = TRUE)
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| configure_data_table <- function(threads = NULL, verbose = FALSE) {
|
| if (!has_data_table()) {
|
| if (verbose) {
|
| cli::cli_inform("data.table not available - using base R")
|
| }
|
| return(invisible(1L))
|
| }
|
|
|
| if (is.null(threads)) {
|
| threads <- max(1L, parallel::detectCores() - 1L)
|
| }
|
|
|
| data.table::setDTthreads(threads)
|
|
|
|
|
| if (verbose) {
|
| cli::cli_inform("data.table configured with {threads} thread{?s}")
|
| }
|
|
|
| invisible(threads)
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| build_hex_neighbor_map_fast <- function(rings) {
|
| num_pieces <- 3 * rings * (rings - 1) + 1
|
| n_rows <- num_pieces * 6L
|
|
|
| if (has_data_table()) {
|
|
|
| dt <- data.table::data.table(
|
| piece_id = integer(n_rows),
|
| side = integer(n_rows),
|
| neighbor_id = integer(n_rows)
|
| )
|
|
|
| row_idx <- 1L
|
| for (piece_id in seq_len(num_pieces)) {
|
| for (side in 0:5) {
|
| neighbor_id <- get_hex_neighbor(piece_id, side, rings)
|
|
|
| data.table::set(dt, row_idx, "piece_id", as.integer(piece_id))
|
| data.table::set(dt, row_idx, "side", as.integer(side))
|
| data.table::set(dt, row_idx, "neighbor_id",
|
| if (is.na(neighbor_id)) NA_integer_ else as.integer(neighbor_id))
|
| row_idx <- row_idx + 1L
|
| }
|
| }
|
|
|
| return(dt)
|
| }
|
|
|
|
|
| build_hex_neighbor_map(rings)
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| generate_puzzles_parallel <- function(n_puzzles, type, grid, size,
|
| seeds = seq_len(n_puzzles),
|
| n_workers = NULL, ...) {
|
| if (length(seeds) != n_puzzles) {
|
| stop("Length of seeds must equal n_puzzles")
|
| }
|
|
|
| if (has_parallel() && n_puzzles > 1) {
|
|
|
| if (is.null(n_workers)) {
|
| n_workers <- min(4L, parallel::detectCores() - 1L)
|
| }
|
|
|
|
|
| old_plan <- future::plan()
|
| on.exit(future::plan(old_plan), add = TRUE)
|
|
|
| if (.Platform$OS.type == "windows") {
|
| future::plan(future::multisession, workers = n_workers)
|
| } else {
|
| future::plan(future::multicore, workers = n_workers)
|
| }
|
|
|
|
|
| results <- furrr::future_map(seeds, function(seed) {
|
| generate_puzzle(
|
| type = type,
|
| grid = grid,
|
| size = size,
|
| seed = seed,
|
| save_files = FALSE,
|
| ...
|
| )
|
| }, .options = furrr::furrr_options(seed = TRUE))
|
|
|
| } else {
|
|
|
| results <- lapply(seeds, function(seed) {
|
| generate_puzzle(
|
| type = type,
|
| grid = grid,
|
| size = size,
|
| seed = seed,
|
| save_files = FALSE,
|
| ...
|
| )
|
| })
|
| }
|
|
|
| results
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| format_coords <- function(x, y, digits = 2) {
|
| paste0(round(x, digits), ",", round(y, digits))
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| build_svg_path <- function(commands) {
|
| paste(commands, collapse = " ")
|
| }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| get_performance_config <- function() {
|
| list(
|
| data_table = list(
|
| available = has_data_table(),
|
| threads = if (has_data_table()) data.table::getDTthreads() else NA
|
| ),
|
| parallel = list(
|
| available = has_parallel(),
|
| cores = parallel::detectCores()
|
| ),
|
| r_version = R.version.string,
|
| platform = .Platform$OS.type
|
| )
|
| }
|
|
|
|
|
|
|
| print_performance_config <- function() {
|
| config <- get_performance_config()
|
|
|
| if (requireNamespace("cli", quietly = TRUE)) {
|
| cli::cli_h2("jigsawR Performance Configuration")
|
|
|
| if (config$data_table$available) {
|
| cli::cli_alert_success("data.table: {config$data_table$threads} threads")
|
| } else {
|
| cli::cli_alert_warning("data.table: not available")
|
| }
|
|
|
| if (config$parallel$available) {
|
| cli::cli_alert_success("future/furrr: {config$parallel$cores} cores available")
|
| } else {
|
| cli::cli_alert_warning("future/furrr: not available")
|
| }
|
|
|
| cli::cli_alert_info("R: {config$r_version}")
|
| cli::cli_alert_info("Platform: {config$platform}")
|
| } else {
|
| cat("jigsawR Performance Configuration\n")
|
| cat("==================================\n")
|
| cat(sprintf("data.table: %s\n",
|
| if (config$data_table$available)
|
| sprintf("%d threads", config$data_table$threads)
|
| else "not available"))
|
| cat(sprintf("future/furrr: %s\n",
|
| if (config$parallel$available)
|
| sprintf("%d cores", config$parallel$cores)
|
| else "not available"))
|
| cat(sprintf("R: %s\n", config$r_version))
|
| cat(sprintf("Platform: %s\n", config$platform))
|
| }
|
|
|
| invisible(config)
|
| }
|
|
|