Create an explicit run-design specification in which each row defines one multi-objective optimization run.
run_manual() is used when the exact objective weights or epsilon levels
should be controlled by the user instead of being generated automatically
with run_grid.
Value
An object of class RunManual and RunDesign. The object
stores the supplied run table and is intended to be passed to the
runs argument of a multi-objective method function.
Details
The input must be a data.frame with one row per requested
optimization run. The required columns depend on the multi-objective method
in which the design is used.
Weighted-sum designs
For set_method_weighted_sum, weight columns must follow the
convention:
weight_<alias>
where <alias> is the alias of a registered objective.
For example, objectives with aliases "cost" and "benefit"
require:
weight_cost
weight_benefitEach row defines the weights used in one weighted-sum run. Whether weights
must already sum to one depends on the normalization settings supplied to
set_method_weighted_sum.
Epsilon-constraint and AUGMECON designs
For set_method_epsilon_constraint and
set_method_augmecon, epsilon columns must follow the
convention:
eps_<alias>
where <alias> identifies a constrained secondary objective.
The primary objective is optimized directly and therefore normally does not require an epsilon column. Each row defines one combination of epsilon bounds for the secondary objectives.
Column names are matched against the registered objective aliases when the
run design is resolved by the corresponding set_method_*() function.
Therefore, aliases containing spaces or other non-syntactic characters
should be avoided when manual run tables are expected to be used.
run_manual() performs only structural validation of the supplied object.
Method-specific validation—including required columns, unknown aliases,
missing values, weight validity, and epsilon compatibility—is performed when
the design is attached to a multi-objective method or resolved before
solving.
Additional columns should not be used unless they are explicitly supported by the selected method. The order of rows is preserved and corresponds to the requested run order.
Manual designs are useful when:
exact preference weights are known;
policy-relevant epsilon thresholds must be evaluated;
irregular regions of the frontier require denser sampling;
runs must reproduce a previously published experimental design;
a small number of selected trade-off scenarios is preferred over a regular automatic grid.
Examples
# Create an explicit weighted-sum design
weighted_runs <- run_manual(
data.frame(
weight_cost = c(1.0, 0.75, 0.50, 0.25, 0.0),
weight_benefit = c(0.0, 0.25, 0.50, 0.75, 1.0)
)
)
weighted_runs
#> $type
#> [1] "manual"
#>
#> $values
#> weight_cost weight_benefit
#> 1 1.00 0.00
#> 2 0.75 0.25
#> 3 0.50 0.50
#> 4 0.25 0.75
#> 5 0.00 1.00
#>
#> attr(,"class")
#> [1] "RunManual" "RunDesign"
# Create an explicit epsilon-constraint design
epsilon_runs <- run_manual(
data.frame(
eps_benefit = c(2, 4, 6, 8)
)
)
epsilon_runs
#> $type
#> [1] "manual"
#>
#> $values
#> eps_benefit
#> 1 2
#> 2 4
#> 3 6
#> 4 8
#>
#> attr(,"class")
#> [1] "RunManual" "RunDesign"
# Use a manual design in a weighted-sum workflow
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(actions$id, each = 2),
feature = rep(features$id, times = 2),
multiplier = c(
1.0, 1.0,
1.5, 1.5
)
)
problem <- create_problem(
pu = pu,
features = features,
dist_features = dist_features,
cost = "cost"
) |>
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"),
runs = run_manual(
data.frame(
weight_cost = c(1.0, 0.5, 0.0),
weight_benefit = c(0.0, 0.5, 1.0)
)
),
normalize_weights = TRUE
)
if (requireNamespace("rcbc", quietly = TRUE)) {
problem <- set_solver_cbc(
problem,
verbose = FALSE
)
solutions <- solve(problem)
# Inspect the requested manual design and resulting objective values
get_runs(solutions)
get_objectives(
solutions,
format = "wide"
)
}
#> run_id solution_id cost benefit
#> 1 1 s1 2 0.0
#> 2 2 s2 3 3.5
#> 3 3 s3 18 7.5
