Skip to contents

Create multiple sets of weight values to generate multiple solutions with multi-objective optimization (e.g., the weights parameter of add_wtd_sum_approach() or add_ref_point_approach()).

Usage

approach_weights_matrix(
  n_problems,
  n_values,
  include_zeros = TRUE,
  include_extremes = TRUE
)

Arguments

n_problems

integer value denoting the number of problem() objects for which to generate values.

n_values

integer value denoting the number of weight values to to generate for each problem() (per n_problems).

include_zeros

logical value indicating if the weight values should include zeros? If include_zeros = TRUE, then some of the sets will assign a weight of zero to some of the objectives, and so solutions based on these sets will be influenced by only some of the objectives (i.e., those with non-zero weight values). Defaults to TRUE.

include_extremes

logical value indicating if the sets of weight values should combinations of weight values that consider only a single objective? If include_extremes = TRUE, then some of the sets will contain zeros for all objectives except a single objective. Defaults to TRUE.

Value

A numeric matrix. Here, rows correspond to different sets of each weight values and columns correspond to different objectives. Note that the sets of weights values are filtered to remove sets of weights that - despite having different values - would result in the same prioritization.

Examples

# in this example, we aim to identify a set of planning units that will
# not exceed a particular budget and meet objectives for
# (i) representing species that are important for ecosystem
# functioning (hereafter, keystone species) and (ii) representing species
# that have high social or cultural value (hereafter, iconic species)

# import data
con_cost <- get_sim_pu_raster()
keystone_spp <- get_sim_features()[[1:3]]
iconic_spp <- get_sim_features()[[4:5]]

# define a total conservation budget (30% of total cost)
budget <- terra::global(con_cost, "sum", na.rm = TRUE)[[1]] * 0.3

# define a single-objective problem for the keystone species objective
p1 <-
  problem(con_cost, keystone_spp) %>%
  add_min_shortfall_objective(budget) %>%
  add_relative_targets(0.4) %>%
  add_binary_decisions()

# define a single-objective problem for the iconic species objective
p2 <-
  problem(con_cost, iconic_spp) %>%
  add_min_shortfall_objective(budget) %>%
  add_relative_targets(0.45) %>%
  add_binary_decisions()

# solve the single-objective problems
s1 <-
  p1 %>%
  add_default_solver(verbose = FALSE) %>%
  solve()
s2 <-
  p2 %>%
  add_default_solver(verbose = FALSE) %>%
  solve()

# plot the solutions to the single-objective problems
plot(s1, main = "Keystone species", axes = FALSE)

plot(s2, main = "Iconic species", axes = FALSE)


# now create multi-objective problem with equal weights for the objectives
mp1 <-
  multi_problem(keystone_obj = p1, iconic_obj = p2) %>%
  add_wtd_sum_approach(c(0.5, 0.5), verbose = TRUE) %>%
  add_default_solver(verbose = FALSE)

# solve problem
ms1 <- solve(mp1)

# plot solution to multi-objective problem
plot(ms1, main = "Equal weights", axes = FALSE)


# we will now generate multiple solutions based on a matrix
# that contains different combinations of weight values

# create a matrix with weight values for objectives
weights_matrix <- approach_weights_matrix(
  n_problems = 2, n_values = 5, include_zero = TRUE
)

# print weight matrix
print(weights_matrix)
#>       [,1] [,2]
#>  [1,] 1.00 1.00
#>  [2,] 1.00 0.00
#>  [3,] 0.00 1.00
#>  [4,] 0.50 0.25
#>  [5,] 0.75 0.25
#>  [6,] 1.00 0.25
#>  [7,] 0.25 0.50
#>  [8,] 0.75 0.50
#>  [9,] 1.00 0.50
#> [10,] 0.25 0.75
#> [11,] 0.50 0.75
#> [12,] 1.00 0.75
#> [13,] 0.25 1.00
#> [14,] 0.50 1.00
#> [15,] 0.75 1.00

# create multi-objective problem using weight matrix
mp2 <-
  multi_problem(keystone_obj = p1, iconic_obj = p2) %>%
  add_wtd_sum_approach(weights_matrix, verbose = TRUE) %>%
  add_default_solver(gap = 0.01, verbose = FALSE)

# solve multi-objective problem and remove duplicate solutions
ms2 <- solve(mp2, remove_duplicates = TRUE)
#> Generating solutions ■■■■■■■                          | 3/15 |  20% | ETA: 5s
#> Generating solutions ■■■■■■■■■■■■■■■■■■■              | 9/15 |  60% | ETA: 2s
#> Generating solutions ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■  | 15/15 | 100% | ETA: 0s
#>  Found 13 out of the requested 15 non-duplicate solutions.

# plot multiple solutions
plot(terra::rast(ms2), axes = FALSE)


# extract objective values for the solutions
obj_matrix <- attributes(ms2)$objective

# print the objective values
print(obj_matrix)
#>             keystone_obj iconic_obj
#> solution_1     0.9059099  0.7111356
#> solution_2     0.8567573  2.0000000
#> solution_3     3.0000000  0.6057715
#> solution_4     0.8949350  0.7202442
#> solution_5     0.8893569  0.7320958
#> solution_6     0.8893569  0.7320958
#> solution_7     1.0348682  0.6327522
#> solution_8     0.8949350  0.7202442
#> solution_9     1.0801232  0.6129796
#> solution_10    0.9616594  0.6677060
#> solution_11    1.0799882  0.6111864
#> solution_12    1.0348183  0.6323333
#> solution_13    0.9616594  0.6677060

# plot the objectives values to visualize trade-offs
# (note that smaller values are better because these objectives seek to
# minimize representation shortfalls)
plot(
  obj_matrix,
  main = "Trade-offs between objectives",
  xlab = "Keystone objective (shortfall)",
  ylab = "Iconic objective (shortfall)"
)


# we can see that there are multiple solutions (points) that have
# exactly the same performance for the two objectives (these appear
# as points with slightly thicker borders), and this is a key limitation
# of the weighted sum approach