Set the objective of a conservation planning problem() to secure as much of the features as possible without exceeding a budget. This type of objective does not use targets, and feature weights should be used instead to increase the representation of different features in solutions. Note that this objective does not aim to maximize as much of each feature as possible and so often results in solutions that are heavily biased towards specific features.

add_max_utility_objective(x, budget)

## Arguments

x problem() (i.e. ConservationProblem) object. numeric value specifying the maximum expenditure of the prioritization. For problems with multiple zones, the argument to budget can be a single numeric value to specify a budget for the entire solution or a numeric vector to specify a budget for each each management zone.

## Value

Object (i.e. ConservationProblem) with the objective added to it.

## Details

A problem objective is used to specify the overall goal of the conservation planning problem. Please note that all conservation planning problems formulated in the prioritizr package require the addition of objectives---failing to do so will return an error message when attempting to solve problem.

The maximum utility objective seeks to find the set of planning units that maximizes the overall level of representation across a suite of conservation features, while keeping cost within a fixed budget. Additionally, weights can be used to favor the representation of certain features over other features (see add_feature_weights()). This objective can be expressed mathematically for a set of planning units ($$I$$ indexed by $$i$$) and a set of features ($$J$$ indexed by $$j$$) as:

$$\mathit{Maximize} \space \sum_{i = 1}^{I} -s \space c_i \space x_i + \sum_{j = 1}^{J} a_j w_j \\ \mathit{subject \space to} \\ a_j = \sum_{i = 1}^{I} x_i r_{ij} \space \forall j \in J \\ \sum_{i = 1}^{I} x_i c_i \leq B$$

Here, $$x_i$$ is the decisions variable (e.g. specifying whether planning unit $$i$$ has been selected (1) or not (0)), $$r_{ij}$$ is the amount of feature $$j$$ in planning unit $$i$$, $$A_j$$ is the amount of feature $$j$$ represented in in the solution, and $$w_j$$ is the weight for feature $$j$$ (defaults to 1 for all features; see add_feature_weights() to specify weights). Additionally, $$B$$ is the budget allocated for the solution, $$c_i$$ is the cost of planning unit $$i$$, and $$s$$ is a scaling factor used to shrink the costs so that the problem will return a cheapest solution when there are multiple solutions that represent the same amount of all features within the budget.

## Notes

In early versions (< 3.0.0.0), this function was named as the add_max_cover_objective function. It was renamed to avoid confusion with existing terminology.

add_feature_weights(), objectives.

## Examples

# load data
data(sim_pu_raster, sim_pu_zones_stack, sim_features, sim_features_zones)

# create problem with maximum utility objective
p1 <- problem(sim_pu_raster, sim_features) %>%
# \dontrun{
# solve problem
s1 <- solve(p1)#> Gurobi Optimizer version 9.0.2 build v9.0.2rc0 (linux64)
#> Optimize a model with 6 rows, 95 columns and 545 nonzeros
#> Model fingerprint: 0x75ade7c1
#> Variable types: 5 continuous, 90 integer (90 binary)
#> Coefficient statistics:
#>   Matrix range     [2e-01, 2e+02]
#>   Objective range  [1e-04, 1e+00]
#>   Bounds range     [1e+00, 7e+01]
#>   RHS range        [5e+03, 5e+03]
#> Found heuristic solution: objective -0.0000000
#> Presolve removed 5 rows and 5 columns
#> Presolve time: 0.00s
#> Presolved: 1 rows, 90 columns, 90 nonzeros
#> Variable types: 0 continuous, 90 integer (90 binary)
#> Presolved: 1 rows, 90 columns, 90 nonzeros
#>
#>
#> Root relaxation: objective 7.435117e+01, 1 iterations, 0.00 seconds
#>
#>     Nodes    |    Current Node    |     Objective Bounds      |     Work
#>  Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time
#>
#>      0     0   74.35117    0    1   -0.00000   74.35117      -     -    0s
#> H    0     0                      74.2352258   74.35117  0.16%     -    0s
#> H    0     0                      74.2714723   74.35117  0.11%     -    0s
#>      0     0   74.28961    0    2   74.27147   74.28961  0.02%     -    0s
#>      0     0   74.28961    0    1   74.27147   74.28961  0.02%     -    0s
#>      0     0   74.28961    0    2   74.27147   74.28961  0.02%     -    0s
#>      0     0   74.28596    0    2   74.27147   74.28596  0.02%     -    0s
#>      0     0   74.28498    0    4   74.27147   74.28498  0.02%     -    0s
#>      0     0   74.28417    0    2   74.27147   74.28417  0.02%     -    0s
#>      0     0   74.28410    0    6   74.27147   74.28410  0.02%     -    0s
#>      0     0   74.28247    0    6   74.27147   74.28247  0.01%     -    0s
#>      0     0   74.28247    0    6   74.27147   74.28247  0.01%     -    0s
#>      0     2   74.28226    0    6   74.27147   74.28226  0.01%     -    0s
#>
#> Cutting planes:
#>   Cover: 3
#>   MIR: 2
#>   StrongCG: 1
#>
#> Explored 21 nodes (55 simplex iterations) in 0.01 seconds
#> Thread count was 1 (of 4 available processors)
#>
#> Solution count 3: 74.2715 74.2352 -0
#>
#> Optimal solution found (tolerance 0.00e+00)
#> Best objective 7.427147227067e+01, best bound 7.427147227067e+01, gap 0.0000%
# plot solution
plot(s1, main = "solution", axes = FALSE, box = FALSE)# }

# create multi-zone problem with maximum utility objective that
# has a single budget for all zones
p2 <- problem(sim_pu_zones_stack, sim_features_zones) %>%
# \dontrun{
# solve problem
s2 <- solve(p2)#> Gurobi Optimizer version 9.0.2 build v9.0.2rc0 (linux64)
#> Optimize a model with 106 rows, 285 columns and 1905 nonzeros
#> Model fingerprint: 0x1b273c19
#> Variable types: 15 continuous, 270 integer (270 binary)
#> Coefficient statistics:
#>   Matrix range     [2e-01, 2e+02]
#>   Objective range  [3e-05, 1e+00]
#>   Bounds range     [1e+00, 8e+01]
#>   RHS range        [1e+00, 5e+03]
#> Found heuristic solution: objective -0.0000000
#> Presolve removed 105 rows and 195 columns
#> Presolve time: 0.00s
#> Presolved: 1 rows, 90 columns, 90 nonzeros
#> Variable types: 0 continuous, 90 integer (90 binary)
#> Presolved: 1 rows, 90 columns, 90 nonzeros
#>
#>
#> Root relaxation: objective 7.691841e+01, 1 iterations, 0.00 seconds
#>
#>     Nodes    |    Current Node    |     Objective Bounds      |     Work
#>  Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time
#>
#>      0     0   76.91841    0    1   -0.00000   76.91841      -     -    0s
#> H    0     0                      74.5659436   76.91841  3.15%     -    0s
#>      0     0   76.90382    0    2   74.56594   76.90382  3.14%     -    0s
#> H    0     0                      76.8663921   76.90382  0.05%     -    0s
#>      0     0   76.89002    0    3   76.86639   76.89002  0.03%     -    0s
#>      0     0   76.89002    0    1   76.86639   76.89002  0.03%     -    0s
#>      0     0   76.89002    0    1   76.86639   76.89002  0.03%     -    0s
#>      0     0   76.89002    0    3   76.86639   76.89002  0.03%     -    0s
#>      0     0   76.89002    0    4   76.86639   76.89002  0.03%     -    0s
#>      0     0   76.88913    0    5   76.86639   76.88913  0.03%     -    0s
#>      0     0   76.88879    0    6   76.86639   76.88879  0.03%     -    0s
#>      0     0   76.88233    0    6   76.86639   76.88233  0.02%     -    0s
#>      0     0   76.88112    0    6   76.86639   76.88112  0.02%     -    0s
#>      0     0   76.87939    0    7   76.86639   76.87939  0.02%     -    0s
#>      0     0   76.87914    0    8   76.86639   76.87914  0.02%     -    0s
#>      0     0   76.87832    0    8   76.86639   76.87832  0.02%     -    0s
#>      0     0   76.87640    0    5   76.86639   76.87640  0.01%     -    0s
#>      0     0   76.87625    0    6   76.86639   76.87625  0.01%     -    0s
#>      0     2   76.87622    0    6   76.86639   76.87622  0.01%     -    0s
#>
#> Cutting planes:
#>   Cover: 1
#>   MIR: 2
#>   StrongCG: 2
#>
#> Explored 4 nodes (37 simplex iterations) in 0.01 seconds
#> Thread count was 1 (of 4 available processors)
#>
#> Solution count 3: 76.8664 74.5659 -0
#>
#> Optimal solution found (tolerance 0.00e+00)
#> Best objective 7.686639207002e+01, best bound 7.686639207002e+01, gap 0.0000%
# plot solution
plot(category_layer(s2), main = "solution", axes = FALSE, box = FALSE)# }

# create multi-zone problem with maximum utility objective that
# has separate budgets for each zone
p3 <- problem(sim_pu_zones_stack, sim_features_zones) %>%
add_max_utility_objective(c(1000, 2000, 3000)) %>%
# \dontrun{
# solve problem
s3 <- solve(p3)#> Gurobi Optimizer version 9.0.2 build v9.0.2rc0 (linux64)
#> Optimize a model with 108 rows, 285 columns and 1905 nonzeros
#> Model fingerprint: 0x0d15a0b2
#> Variable types: 15 continuous, 270 integer (270 binary)
#> Coefficient statistics:
#>   Matrix range     [2e-01, 2e+02]
#>   Objective range  [3e-05, 1e+00]
#>   Bounds range     [1e+00, 8e+01]
#>   RHS range        [1e+00, 3e+03]
#> Found heuristic solution: objective -0.0000000
#> Presolve removed 15 rows and 15 columns
#> Presolve time: 0.00s
#> Presolved: 93 rows, 270 columns, 540 nonzeros
#> Variable types: 0 continuous, 270 integer (270 binary)
#> Presolved: 93 rows, 270 columns, 540 nonzeros
#>
#>
#> Root relaxation: objective 8.792265e+01, 9 iterations, 0.00 seconds
#>
#>     Nodes    |    Current Node    |     Objective Bounds      |     Work
#>  Expl Unexpl |  Obj  Depth IntInf | Incumbent    BestBd   Gap | It/Node Time
#>
#>      0     0   87.92265    0    3   -0.00000   87.92265      -     -    0s
#> H    0     0                      86.3925730   87.92265  1.77%     -    0s
#> H    0     0                      86.4414954   87.92265  1.71%     -    0s
#>      0     0   86.52619    0    1   86.44150   86.52619  0.10%     -    0s
#> H    0     0                      86.4414968   86.52619  0.10%     -    0s
#>      0     0   86.51632    0    2   86.44150   86.51632  0.09%     -    0s
#>      0     0   86.48573    0    4   86.44150   86.48573  0.05%     -    0s
#>      0     0   86.48573    0    3   86.44150   86.48573  0.05%     -    0s
#>      0     0   86.48573    0    6   86.44150   86.48573  0.05%     -    0s
#> H    0     0                      86.4668758   86.48573  0.02%     -    0s
#> H    0     0                      86.4735445   86.48573  0.01%     -    0s
#>      0     0   86.48289    0    2   86.47354   86.48289  0.01%     -    0s
#>      0     0   86.48289    0    3   86.47354   86.48289  0.01%     -    0s
#> H    0     0                      86.4735471   86.48289  0.01%     -    0s
#>      0     0   86.48289    0    4   86.47355   86.48289  0.01%     -    0s
#>      0     0   86.48289    0    2   86.47355   86.48289  0.01%     -    0s
#>      0     0   86.48263    0    6   86.47355   86.48263  0.01%     -    0s
#>      0     0   86.47613    0    4   86.47355   86.47613  0.00%     -    0s
#>      0     0   86.47595    0    6   86.47355   86.47595  0.00%     -    0s
#>      0     0   86.47567    0    6   86.47355   86.47567  0.00%     -    0s
#>      0     0   86.47552    0    2   86.47355   86.47552  0.00%     -    0s
#>      0     0   86.47551    0    6   86.47355   86.47551  0.00%     -    0s
#>
#> Cutting planes:
#>   Gomory: 1
#>   Cover: 1
#>   MIR: 2
#>   StrongCG: 2
#>   RLT: 1
#>
#> Explored 1 nodes (150 simplex iterations) in 0.02 seconds
#> Thread count was 1 (of 4 available processors)
#>
#> Solution count 7: 86.4735 86.4735 86.4669 ... -0
#>
#> Optimal solution found (tolerance 0.00e+00)
#> Best objective 8.647354705008e+01, best bound 8.647354705008e+01, gap 0.0000%
# plot solution
plot(category_layer(s3), main = "solution", axes = FALSE, box = FALSE)# }