add_cost_constraints: Add cost constraints

View source: R/add_cost_constraints.R

add_cost_constraintsR Documentation

Add cost constraints

Description

Add constraints to a conservation planning problem to ensure that the cost of selected planning units meets certain criteria.

Usage

add_cost_constraints(x, budget, sense)

Arguments

x

problem() object.

budget

numeric value specifying the maximum expenditure permitted for the solution. If x has multiple zones, then budget can be (i) a single numeric value to specify an overall budget for the entire solution or (ii) a numeric vector to specify a budget for each zone (separately) in the solution. If x will be used to generate a multi-objective problem (via multi_problem()), budget = NULL can be used to avoid specifying a maximum expenditure.

sense

character value specifying the constraint sense. Acceptable values are: ">=", "<=", or "=". If x has multiple zones, then sense can be (i) a single character value to specify a constraint sense for the entire solution or (ii) a character vector to specify a different constraint sense for each zone (separately) in the solution. Note that sense and budget must have the same number of values.

Details

This function adds constraints constraints that can be used to ensure that the cost of solutions meet certain criteria (see Examples section below for details). For example, these constraints can be used to specify both minimum and maximum budget thresholds. Note that this function provided as a convenient alternative for adding linear constraints (per add_linear_constraints()) to a problem().

Value

An updated problem() object with the constraints added to it.

Mathematical formulation

The cost constraints are implemented using the following equation. Let I denote the set of planning units (indexed by i), Z the set of management zones (indexed by z), and X_{iz} the decision variable for allocating planning unit i to zone z (e.g., with binary values indicating if each planning unit is allocated or not). Also, let D_{iz} denote the costs associated with planning units i \in I for zones z \in Z (per data, if supplied as a matrix object), \theta denote the constraint sense (per sense), and B denote the budget threshold (per budget).

\sum_{i}^{I} \sum_{z}^{Z} (D_{iz} \times X_{iz}) \space \theta \space t

See Also

Other functions for adding constraints: add_contiguity_constraints(), add_feature_contiguity_constraints(), add_linear_constraints(), add_locked_in_constraints(), add_locked_out_constraints(), add_mandatory_allocation_constraints(), add_manual_bounded_constraints(), add_manual_locked_constraints(), add_neighbor_constraints()

Examples


# set seed for reproducibility
set.seed(600)

# load data
sim_complex_pu_raster <- get_sim_complex_pu_raster()
sim_complex_features <- get_sim_complex_features()

# create layer with 1s for all planning units
sim_ones_complex_raster <- (sim_complex_pu_raster * 0) + 1

# here we will formulate a multi-objective optimization problem
# that (i) minimizes the largest target shortfall for feature representation,
# (ii) minimizes the overall target shortfalls for feature representation,
# and (iii) minimizes the cost of the solution. since the
# first objective is to minimize the largest shortfall and the second
# objective is to minimize overall target shortfalls,
# this helps balance shortfalls among all features and better
# achieve complementarity. additionally, we will specify that
# (approximately) 30% of the study area should be selected (i.e., by
# specifying a budget for the upper threshold and a linear constraint for
# the lower threshold on the number of selected planning units).

# calculate budget based on 30% of the number of planning units
budget <-
  0.3 * terra::global(sim_ones_complex_raster, "sum", na.rm = TRUE)[[1]]

# build multi-objective conservation planning problem
mp <-
  multi_problem(
    obj1 =
      problem(sim_ones_complex_raster, sim_complex_features) %>%
      add_min_largest_shortfall_objective(budget = budget) %>%
      add_auto_targets("jung") %>%
      # note that this constraint only needs to be specified once
      add_cost_constraints(sense = ">=", budget = budget * 0.9) %>%
      add_binary_decisions(),
    obj2 =
      problem(sim_ones_complex_raster, sim_complex_features) %>%
      add_min_shortfall_objective(budget = budget) %>%
      # note that we use the same targets for both obj1 and obj2
      add_auto_targets("jung") %>%
      add_binary_decisions(),
    obj3 =
      problem(sim_complex_pu_raster, sim_complex_pu_raster) %>%
      add_min_penalties_objective(budget = NULL) %>%
      # note a value of 1 is here because only the costs minimized
      add_cost_penalties(1) %>%
      add_binary_decisions()
  ) %>%
  add_default_solver(gap = 0.01, verbose = FALSE)

# to explore trade-offs between how well the feature targets
# are met and cost, we will generate a matrix of relative tolerance values
# for the hierarchical approach. note that the first column of this
# matrix will have only zeros to help promote balanced
# shortfalls across different features, and the second column
# will have non-zeros because we are interested in trade-offs between
# overall feature shortfalls and cost
rel_tol_matrix <- matrix(0, ncol = 2, nrow = 10)
rel_tol_matrix[, 2] <- seq(0, 0.5, length.out = nrow(rel_tol_matrix))

# display matrix
print(rel_tol_matrix)

# add hierarchical approach to multi-objective problem
mp <-
  mp %>%
  add_hier_approach(rel_tol = rel_tol_matrix)

# generate solutions and remove duplicates
ms <- solve(mp, remove_duplicates = TRUE)

# plot the solutions
plot(terra::rast(ms), axes = FALSE)

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

# print the objective values
print(obj_matrix)

# plot the objectives values to visualize trade-offs
# (note that smaller values are better for both objectives)
plot(
  obj_matrix[, 2:3],
  main = "Trade-offs between objectives",
  xlab = "Species representation (overall shortfall)",
  ylab = "Solution cost"
)


prioritizr documentation built on Sept. 24, 2026, 5:07 p.m.