Nothing
## ----setup, include=FALSE-----------------------------------------------------
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
library(multiscape)
can_solve <- requireNamespace("rcbc", quietly = TRUE) &&
requireNamespace("ggplot2", quietly = TRUE)
## ----build-problem------------------------------------------------------------
sim <- load_sim_multiaction()
# A common catalogue: each action is a separate binary decision in a unit.
actions <- data.frame(
id = c("restore", "control", "fence", "monitor")
)
# Two illustrative opportunity areas in the 8-by-8 landscape.
southwest <- with(sim$planning_units, x < 4 & y < 4)
northeast <- with(sim$planning_units, x > 4 & y > 4)
# Assign a return to every planning-unit--action pair.
returns <- expand.grid(
pu = sim$planning_units$id,
action = actions$id,
KEEP.OUT.ATTRS = FALSE,
stringsAsFactors = FALSE
)
idx <- match(returns$pu, sim$planning_units$id)
returns$profit <- -3 # No intervention is preferred outside opportunity areas.
returns$profit[returns$action == "restore" & southwest[idx]] <- 8
returns$profit[returns$action == "control" & southwest[idx]] <- -2
returns$profit[returns$action == "fence" & northeast[idx]] <- 7
returns$profit[returns$action == "monitor" & northeast[idx]] <- 4
# Build the problem without any special action-selection rules.
raw <- create_problem(
pu = sim$planning_units,
features = sim$features,
dist_features = sim$dist_features,
cost = "cost"
) |>
add_actions(actions, cost = 1) |>
add_profit(returns)
## ----register-sets------------------------------------------------------------
base <- raw |>
add_action_sets(list(
restore_control = c("restore", "control"),
restore_monitor = c("restore", "monitor"),
fence_monitor = c("fence", "monitor")
))
# Membership is a compact table; no new decision variable has been added.
get_action_sets(base)
## ----alternative-set-format---------------------------------------------------
memberships <- data.frame(
set = c("restore_control", "restore_control",
"restore_monitor", "restore_monitor",
"fence_monitor", "fence_monitor"),
action = c("restore", "control", "restore", "monitor", "fence", "monitor")
)
alternative <- add_action_sets(raw, memberships)
## ----permit-concurrency-------------------------------------------------------
concurrent <- base |>
add_constraint_action_cardinality(2, "max", name = "two_per_unit")
## ----cardinality-variations---------------------------------------------------
# Up to two actions in the south-west, but the default one elsewhere.
local_capacity <- base |>
add_constraint_action_cardinality(
2, "max", pu = sim$planning_units$id[southwest]
)
# Allow two in total, but at most one of restoration or control.
subset_capacity <- base |>
add_constraint_action_cardinality(2, "max") |>
add_constraint_action_cardinality(
1, "max", actions = c("restore", "control")
)
# Exactly two actions in each south-west unit.
exact_two <- base |>
add_constraint_action_cardinality(
2, "equal", pu = sim$planning_units$id[southwest]
)
## ----requirements-------------------------------------------------------------
# Whenever restoration is chosen in a south-west unit, control is required.
dependent <- concurrent |>
add_constraint_action_requires(
actions = "restore", requires = "control",
pu = sim$planning_units$id[southwest]
)
# A different example: either control or monitoring can accompany restoration.
flexible <- concurrent |>
add_constraint_action_requires(
actions = "restore", requires = c("control", "monitor"),
sense = "any", pu = sim$planning_units$id[southwest]
)
## ----exclusions-and-together--------------------------------------------------
# Fencing and monitoring cannot be combined in north-east units.
exclusive <- concurrent |>
add_constraint_action_excludes(
c("fence", "monitor"), pu = sim$planning_units$id[northeast]
)
# Reuse the MEMBERS of a registered set, not the set identifier itself.
registered <- get_action_sets(base)
members <- registered$action[registered$set == "restore_control"]
joint_selection <- concurrent |>
add_constraint_action_together(
members, pu = sim$planning_units$id[southwest]
)
## ----configure-scenarios------------------------------------------------------
# A: one action at most (the package default).
single <- base
# B: up to two actions in every unit.
# Positive-return actions may now be combined where advantageous.
# C: two actions allowed, but restoration needs control in the south-west;
# fencing and monitoring are incompatible in the north-east.
compatible <- concurrent |>
add_constraint_action_requires(
"restore", "control", pu = sim$planning_units$id[southwest]
) |>
add_constraint_action_excludes(
c("fence", "monitor"), pu = sim$planning_units$id[northeast]
)
models <- list(
single = single,
concurrent = concurrent,
compatible = compatible
)
## ----solve-scenarios, eval=can_solve------------------------------------------
solutions <- lapply(models, function(problem) {
problem |>
add_objective_max_profit(alias = "profit") |>
set_solver_cbc(time_limit = 30, verbose = FALSE) |>
solve()
})
# A concise comparison: objective values and selected action counts.
comparison <- do.call(rbind, lapply(names(solutions), function(label) {
result <- solutions[[label]]
selected <- get_actions(result, solution = 1)
selected <- selected[selected$selected > 0.5, , drop = FALSE]
counts <- table(factor(selected$action, levels = actions$id))
data.frame(
scenario = label,
profit = get_objectives(result, format = "wide")$profit[1],
restore = unname(counts["restore"]),
control = unname(counts["control"]),
fence = unname(counts["fence"]),
monitor = unname(counts["monitor"]),
row.names = NULL
)
}))
comparison
## ----map-single, eval=can_solve, fig.width=7.5, fig.height=4.8, fig.cap="A. Default: at most one action in each planning unit."----
plot_spatial_actions(solutions$single, layout = "single")
## ----map-concurrent, eval=can_solve, fig.width=7.5, fig.height=4.8, fig.cap="B. Up to two actions: concurrent selections become possible."----
plot_spatial_actions(solutions$concurrent, layout = "single")
## ----map-compatible, eval=can_solve, fig.width=7.5, fig.height=4.8, fig.cap="C. Action dependencies and exclusions restrict which concurrent choices are possible."----
plot_spatial_actions(solutions$compatible, layout = "single")
## ----joint-outcome------------------------------------------------------------
joint_effects <- concurrent |>
add_effects(data.frame(
action = c("restore", "control", "restore_control"),
feature = "woodland",
effect = c(0.10, 0.05, 0.20)
))
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.