The hardware and bandwidth for this mirror is donated by dogado GmbH, the Webhosting and Full Service-Cloud Provider. Check out our Wordpress Tutorial.
If you wish to report a bug, or if you are interested in having us mirror your free-software or open-source project, please feel free to contact us at mirror[@]dogado.de.
Each constructor has a fixed repeated-call contract. No argument is needed to choose between accumulation and replacement: existing definitions are never silently replaced.
| Family | Repeated-call behavior |
|---|---|
add_actions(), add_effects(),
add_profit() |
One complete definition per problem; a second call is an error. |
set_solver() and its backend wrappers |
One explicit configuration; a second call is an error. Defaults do not count as configuration. |
set_method_*() |
One MO method, including its run design; switching or repeating it is an error. |
add_objective_*() without
alias |
One explicit single-objective definition; a second one is an error. |
add_objective_*() with
alias |
Distinct aliases accumulate; a repeated alias is an error. |
add_action_sets() |
Distinct set IDs accumulate; a repeated ID is an error. |
| Targets, area, budget, action cardinality, and logical action relations | Distinct constraint definitions accumulate; repeated identities are errors. |
| Spatial constructors | Distinct relation names accumulate; a repeated name is an error. |
| Planning-unit and action locks | Compatible locks accumulate; identical states are idempotent and contradictory states are errors. |
The legacy add_benefits() and add_losses()
wrappers share the one effects definition with
add_effects(). Even a zero-profit specification or an empty
filtered effects table counts as an explicit definition.
Keep an object before the definition you want to vary. Constructors return an independent problem, so alternatives can share that common base.
base <- create_problem(
pu = data.frame(id = 1:3, cost = 1, area = 10),
features = data.frame(id = 1L, name = "woodland"),
dist_features = data.frame(pu = 1:3, feature = 1L, amount = 100)
)
actions_base <- base |>
add_actions(data.frame(id = c("restore", "control", "fence")), cost = 1)
low_effect <- actions_base |>
add_effects(data.frame(action = "restore", feature = "woodland", effect = 20))
high_effect <- actions_base |>
add_effects(data.frame(action = "restore", feature = "woodland", effect = 40))
is.null(actions_base$data$dist_effects)
#> [1] TRUECalling add_effects(low_effect, ...) again would raise
an error. To change actions, start from base; to change
effects or profit, start from actions_base.
Define all solver parameters in one call. Setting a solver does not run it.
objectives_base <- high_effect |>
add_constraint_targets_absolute(50) |>
add_objective_min_cost(alias = "cost") |>
add_objective_max_effect(alias = "benefit")
cbc_problem <- objectives_base |>
set_solver_cbc(gap_limit = 0, time_limit = 60)
gurobi_problem <- objectives_base |>
set_solver_gurobi(gap_limit = 0, time_limit = 60)
weighted_problem <- cbc_problem |>
set_method_weighted_sum(
aliases = c("cost", "benefit"),
runs = set_runs_grid(n = 3)
)
epsilon_problem <- cbc_problem |>
set_method_epsilon_constraint(
primary = "cost",
aliases = c("cost", "benefit"),
runs = set_runs_manual(data.frame(eps_benefit = c(40, 80)))
)
augmecon_problem <- cbc_problem |>
set_method_augmecon(
primary = "cost",
aliases = c("cost", "benefit"),
runs = set_runs_grid(n = 3)
)
is.null(cbc_problem$data$method)
#> [1] TRUE
is.null(objectives_base$data$solve_args)
#> [1] TRUEEach method is derived from cbc_problem, which has no
configured MO method. To compare run designs within a method, use this
same branching pattern.
Constraint identity describes what is constrained, rather than the threshold or its diagnostic name. Identifier order does not affect identity. Explicit constraint names must be unique within their family; omitted names are generated automatically. A different name does not permit a duplicate constraint identity.
| Constraint | Identity |
|---|---|
| Action cardinality | Set of PUs + total/subset action scope + sense |
| Logical action relation | Type + action groups (including required companions) + all/any sense + set of PUs |
| Budget | Action scope + included cost components + sense |
| Area | Action scope + area measure (area_col) +
sense |
| Target | Feature + action scope, shared by absolute and relative targets |
Requires, excludes, and together share one name namespace. A single
required companion has the same identity under
sense = "all" and sense = "any".
constrained <- actions_base |>
add_action_sets(list(restore_control = c("restore", "control"))) |>
add_action_sets(list(restore_fence = c("restore", "fence"))) |>
add_constraint_action_cardinality(3, "max", pu = 1) |>
add_constraint_action_cardinality(2, "max", pu = 2) |>
add_constraint_budget(20, "max") |>
add_constraint_budget(10, "max", include_action_cost = FALSE)
get_action_sets(constrained)
#> set action
#> 1 restore_control control
#> 2 restore_control restore
#> 3 restore_fence fence
#> 4 restore_fence restore
constrained$data$constraints$action_cardinality[, c("count", "sense", "name")]
#> count sense name
#> 1 3 max action_cardinality_1
#> 2 2 max action_cardinality_2Adding another total maximum for PU 1 would be an error, even with a different count or name. Different scopes may overlap: all accumulated constraints apply simultaneously. Constraints that are individually valid can still make the model infeasible; the solver determines joint feasibility.
Absolute and relative targets cannot be used to redefine the same feature and action scope. Targets for the same feature with different contributing action subsets can accumulate.
locked <- actions_base |>
add_constraint_locked_planning_units(locked_in = 1) |>
add_constraint_locked_planning_units(locked_out = 3) |>
add_constraint_locked_actions(locked_out = list(fence = 2)) |>
add_constraint_locked_actions(locked_out = list(fence = 2))
locked$data$pu[, c("id", "locked_in", "locked_out")]
#> id locked_in locked_out
#> 1 1 TRUE FALSE
#> 2 2 FALSE FALSE
#> 3 3 FALSE TRUEOmitted lock arguments preserve existing states. Repeating the same lock does not change its meaning. Attempting to lock PU 1 out now would raise an error, as would locking an action in inside excluded PU 3. This is checked in either call order. To alter a lock, rebuild from the object before the original lock.
Spatial relations similarly accumulate under distinct names. Reusing
a name raises an error, whether using
add_spatial_relations() directly or a spatial constructor
such as add_spatial_boundary().
For migration from earlier behavior, move all solver settings into one call, combine effects into one complete table, and create alternatives from a common base rather than applying a second configuration to an existing problem.
These binaries (installable software) and packages are in development.
They may not be fully stable and should be used with caution. We make no claims about them.
Health stats visible at Monitor.