Solve a planning problem stored in a Problem object.
This is the main execution step of the multiscape workflow. It reads
the problem specification stored in a Problem object, builds the
corresponding optimization model when needed, applies the configured solver
settings, and returns either a solution-class or a
solutionset-class depending on whether the workflow is
single-objective or multi-objective.
Arguments
- x
A
Problemobject created withcreate_problemand optionally enriched with actions, effects, targets, constraints, objectives, spatial relations, method settings, and solver settings.- ...
Additional arguments reserved for internal or legacy solver handling. These are not part of the main recommended user interface.
Value
Either:
a
solution-classobject when solving a single-objective problem, ora
solutionset-classobject when solving a configured multi-objective problem.
A Solution represents one optimization run. A SolutionSet
represents multiple runs together with their run table, design information,
and individual Solution objects.
After solving, users will typically inspect or visualize the returned results
through methods associated with Solution and
SolutionSet objects.
Details
Role of solve()
The typical multiscape workflow is:
x <- create_problem(...)
x <- add_...(x, ...)
x <- set_...(x, ...)
res <- solve(x)Thus, solve() is the stage at which the stored problem specification
is turned into one or more optimization runs.
For most users, solve() is the standard execution entry point.
Explicit compilation with compile_model() is optional and is mainly
useful for advanced inspection or debugging workflows.
What solve() uses from the problem object
The function uses the information already stored in the Problem
object, including:
baseline planning data,
actions, effects, profit, and spatial relations,
targets and constraints,
registered objectives,
an optional multi-objective method configuration,
solver settings.
If a model has not yet been built, it is built internally during the solve process. If a model snapshot or pointer already exists, the solving layer may reuse or refresh it depending on the internal model state.
Single-objective vs multi-objective behaviour
The behaviour of solve() depends on the problem configuration.
Single-objective case. If exactly one objective is active and no multi-objective method is configured,
solve()runs a single optimization problem and returns asolution-classobject.Multi-objective case. If a multi-objective method is configured,
solve()dispatches internally according to the stored method name and returns asolutionset-classobject.
Currently supported multi-objective method names are:
"weighted","epsilon_constraint","augmecon".
Consistency rule
If multiple objectives are registered but no multi-objective method has been
selected, solve() stops with an error. In practical terms:
one objective and no multi-objective method \(\Rightarrow\) single-objective solve,
multiple objectives and a valid multi-objective method \(\Rightarrow\) multi-objective solve,
multiple objectives and no multi-objective method \(\Rightarrow\) error.
Solver settings
Solver configuration is read from the Problem object, typically after
calling set_solver or one of its convenience wrappers such as
set_solver_gurobi or set_solver_cbc.
These settings may include:
the selected backend,
time limits,
optimality-gap settings,
CPU cores,
verbosity options,
backend-specific solver parameters.
Method dispatch
solve() is an S3 generic. The public method documented here is
solve.Problem(), which operates on Problem objects.
Examples
# ------------------------------------------------------------
# Minimal single-objective example
# ------------------------------------------------------------
pu <- data.frame(
id = 1:4,
cost = c(1, 2, 3, 4)
)
features <- data.frame(
id = 1:2,
name = c("sp1", "sp2")
)
dist_features <- data.frame(
pu = c(1, 1, 2, 3, 4),
feature = c(1, 2, 2, 1, 2),
amount = c(5, 2, 3, 4, 1)
)
actions <- data.frame(
id = c("conservation", "restoration")
)
effects <- data.frame(
action = rep(c("conservation", "restoration"), each = 2),
feature = rep(features$id, times = 2),
multiplier = c(0.10, 0.10, 0.50, 0.50)
)
x <- create_problem(
pu = pu,
features = features,
dist_features = dist_features
) |>
add_actions(
actions = actions,
cost = c(conservation = 1, restoration = 2)
) |>
add_effects(
effects = effects,
effect_type = "after"
) |>
add_constraint_targets_relative(0.05) |>
add_objective_min_cost(alias = "cost")
if (requireNamespace("rcbc", quietly = TRUE)) {
x <- set_solver_cbc(x, verbose = FALSE)
sol <- solve(x)
print(sol)
}
#> A multiscape solution (<Solution>)
#> ├─result
#> │├─status: .pa_solution_status_inline(st)
#> │├─objective value: "3"
#> │├─gap: 0%
#> │└─runtime: 0.02 sec
#> └─selection
#> │├─planning units: 1 of 4 selected
#> │├─actions: 1 of 8 selected
#> │└─targets met: 2 of 2
#> └─objective values
#> │└─cost: 3
#> └─solver
#> │├─name: `cbc`
#> │├─cores: 2
#> │└─time limit: 2147483647
#> # ℹ Use `x$summary` to inspect user-facing solution summaries.
# ------------------------------------------------------------
# Minimal multi-objective example
# ------------------------------------------------------------
x_mo <- create_problem(
pu = pu,
features = features,
dist_features = dist_features
) |>
add_actions(
actions = actions,
cost = c(conservation = 1, restoration = 2)
) |>
add_effects(
effects = effects,
effect_type = "after"
) |>
add_constraint_targets_relative(0.05) |>
add_objective_min_cost(alias = "cost") |>
add_objective_max_benefit(alias = "benefit") |>
set_method_weighted_sum(
aliases = c("cost", "benefit"),
weights = c(0.5, 0.5),
normalize_weights = TRUE
)
if (requireNamespace("rcbc", quietly = TRUE)) {
x_mo <- set_solver_cbc(x_mo, verbose = FALSE)
solset <- solve(x_mo)
print(solset)
}
#> A multiscape solution set (<SolutionSet>)
#> ├─method
#> │├─name: `weighted`
#> │└─objectives: 2 (cost, benefit)
#> └─content
#> │├─design rows: 1
#> │├─runs: 1
#> │└─solutions: 1
#> └─run summary
#> │├─statuses: optimal: 1
#> │├─runtime: 0.02
#> │├─gap: 0
#> │├─design cols: none
#> │└─value cols: value_cost, value_benefit
#> # ℹ Use `x$solution$runs`, `x$solution$design`, and `x$solution$solutions[[i]]`
#> to inspect details.
