Introduction

prioritizr is an R package for solving systematic conservation prioritization problems using the techniques of integer linear programming (ILP). In particular, both the minimum set cover (Marxan-like) and maximum coverage reserve design problems can be solved. The package offers a unified interface to a variety of commercial and open-source ILP solvers. In contrast to heuristic methods, such as simulated annealing, the ILP methods used by prioritizr can find exact solutions to optimization problems.

This package consists largely of two layers of functions: those that define a reserve design problem and those that solve a reserve design problem using any one of a variety of solvers. The details of the solvers are intentionally abstracted away so that the user requires minimal knowledge of the specific solvers or ILP in general.

The currently supported solvers are as follows. Each must be installed separately from this package to be accessible.

This vignette is a simple, quickstart guide, for full details on this package, consult the complete vignette with vignette("prioritizr-full"). What follows are some simple example of how this package can be used to solve conservation prioritization problems.

library(prioritizr)
# for plotting
library(rasterVis)
library(viridis)

Data generation

The function gaussian_field() can be used to generate spatially auto-correlated random fields, to be used as semi-realistic spatial variables. All conservation prioritization problems involve balancing a trade-off between representing features of conservation interest and minimizing the cost of protection. Therefore we start by generating distributions for four species and a cost layer, all on a 100x100 raster grid of planning units.

set.seed(1)
# raster 100x100 template
e <- raster::extent(0, 100, 0, 100)
r <- raster::raster(e, nrows = 100, ncols = 100, vals = 1)
# generate 9 feature distributions with different scales and range sizes
species <- mapply(function(x, y, r) gaussian_field(r = r, range = x, prop = y),
            rep(c(5, 25), each = 2),
            rep(c(0.1, 0.5), times = 2),
            MoreArgs = list(r = r))
species <- raster::stack(species)
species <- setNames(species, letters[1:raster::nlayers(species)])
levelplot(species, main = 'Species Distributions', layout = c(2, 2),
          scales = list(draw = FALSE),
          col.regions = c("grey20", "#fd9900"), colorkey = FALSE)

plot of chunk generate-data

# genrate cost layer
cost <- gaussian_field(r, 20, mean = 1000, variance = 500)
cost <- setNames(cost, "cost")
levelplot(cost, main = "Cost", margin = FALSE,
          col.regions = viridis::viridis(100))

plot of chunk generate-data

Minimum set cover problem

In the context of systematic reserve design, the minimum set cover problem seeks to find the set of planning units that minimizes the overall cost of a reserve network, while meeting a set of representation targets for the conservation features. The cost is often either the area of the planning units or the opportunity cost of foregone commercial activities (e.g. logging or agriculture). The representation targets ensure that each species is adequately represented in the reserve network.

This problem is equivalent to a simplified Marxan reserve design problem, with the Boundary Length Modifier (BLM) set to zero. To specify a prioritization model of this type we use the minsetcover_model() function to create a minsetcover_model S3 object. This function takes data in a variety of formats (raster, vector, or tabular) and generates a standard object encapsulating the prioritization problem. Here I set targets such that 20% of each species’ existing range will be protected.

msc_model <- minsetcover_model(x = cost, features = species, targets = 0.2)
class(msc_model)
#> [1] "minsetcover_model" "prioritizr_model"

Maximum coverage problem

The maximum coverage problem 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. The cost is often either the area of the planning units or the opportunity cost of foregone commercial activities (e.g. from logging or agriculture). Representation within each planning unit is typically given by the occupancy of each species, however, some measure of abundance or probability of occurrence may also be used.

This problem is roughly the opposite of what the conservation planning software Marxan does. To specify a prioritization model of this type we use the maxcover_model() function to create a maxcover_model S3 object. This function takes data in a variety of formats (raster, vector, or tabular) and generates a standard object encapsulating the prioritization problem. Here we set the budget to 25% of the total cost of the study area .

b_25 <- 0.25 * raster::cellStats(cost, "sum")
mc_model <- maxcover_model(x = cost, features = species, budget = b_25)
class(mc_model)
#> [1] "maxcover_model"   "prioritizr_model"

Maximum target coverage problem

The maximum target coverage problem is a modified version of the the maximum coverage problem. Each conservation feature is assigned a representation target and the objective is to find the set of planning units that meets the most targets while remaining within a fixed budget.

This problem is meant to be a hybrid between the maximum coverage problem and a Marxan-like minimum set cover problem in that it allows for both a budget and targets to be set. To specify a prioritization model of this type we use the maxtargets_model() function to create a maxtargets_model S3 object. This function takes data in a variety of formats (raster, vector, or tabular) and generates a standard object encapsulating the prioritization problem. Here we set the budget to 10% of the total cost of the study area and choose targets such that 20% of each species’ existing range will be protected.

b_10 <- 0.1 * raster::cellStats(cost, "sum")
mtc_model <- maxtargets_model(x = cost, features = species, targets = 0.2, 
                           budget = b_25)
class(mtc_model)
#> [1] "maxtargets_model" "prioritizr_model"

Solving prioritization problems

The function prioritize() offers a unified interface to solving any of three problem types using any of the available solvers. To solve the minimum set cover problem to within 0.1% of optimality use:

msc_results <- prioritize(msc_model, gap = 0.001)

By default, this function uses the best available solver, which is Gurobi if it is installed. Alternatively, the solver can be specified explicitly. For example, to solve the maximum coverage problem with SYMPHONY use:

mc_results <- prioritize(mc_model, solver = "symphony", gap = 0.001)

And to solve the maximum target coverage problem with GLPK use:

mtc_results <- prioritize(mtc_model, solver = "glpk", gap = 0.001)

The resulting solution can be displayed with plot_selection():

plot_selection(cost, msc_results$x, title = "Minimum Set Cover Solution")

plot of chunk solutions

plot_selection(cost, mc_results$x, title = "Maximum Coverage Solution")

plot of chunk solutions

plot_selection(cost, mtc_results$x, title = "Maximum Target Coverage Solution")

plot of chunk solutions

Finally, the objective function values for these solutions can be access with:

# minimum set cover objective
msc_results$objval
#> [1] 985393.9
# maximum coverage objective
mc_results$objval
#> [1] 5667
# maximum target coverage objective
mtc_results$objval
#> [1] 3.998998