A constraint can be added to a conservation planning problem() to ensure that solutions exhibit a specific characteristic.

Details

Constraints can be used to ensure that solutions exhibit a range of different characteristics. For instance, they can be used to lock in or lock out certain planning units from the solution, such as protected areas or degraded land (respectively). Additionally, similar to the penalties functions, some of the constraint functions can be used to increase connectivity in a solution. The key difference between a penalty and a constraint, however, is that constraints work by invalidating solutions that do not exhibit a specific characteristic, whereas penalty functions work by than penalizing solutions which do not meet a specific characteristic. Thus constraints do not affect the objective function. The following constraints are available.

The following constraints can be added to a conservation planning problem():

add_locked_in_constraints()

Add constraints to ensure that certain planning units are selected in the solution.

add_locked_out_constraints()

Add constraints to ensure that certain planning units are not selected in the solution.

add_neighbor_constraints()

Add constraints to ensure that all selected planning units have at least a certain number of neighbors.

add_contiguity_constraints()

Add constraints to a ensure that all selected planning units are spatially connected to each other and form a single contiguous unit.

add_feature_contiguity_constraints()

Add constraints to #' ensure that each feature is represented in a contiguous unit of dispersible habitat. These constraints are a more advanced version of those implemented in the add_contiguity_constraints() function, because they ensure that each feature is represented in a contiguous unit and not that the entire solution should form a contiguous unit.

add_mandatory_allocation_constraints()

Add constraints to ensure that every planning unit is allocated to a management zone in the solution. This function can only be used with problems that contain multiple zones.

See also

Examples

# load data data(sim_pu_raster, sim_features, sim_locked_in_raster, sim_locked_out_raster) # create minimal problem with only targets and no additional constraints p1 <- problem(sim_pu_raster, sim_features) %>% add_min_set_objective() %>% add_relative_targets(0.2) %>% add_binary_decisions() # create problem with locked in constraints p2 <- p1 %>% add_locked_in_constraints(sim_locked_in_raster) # create problem with locked in constraints p3 <- p1 %>% add_locked_out_constraints(sim_locked_out_raster) # create problem with neighbor constraints p4 <- p1 %>% add_neighbor_constraints(2) # create problem with contiguity constraints p5 <- p1 %>% add_contiguity_constraints() # create problem with feature contiguity constraints p6 <- p1 %>% add_feature_contiguity_constraints() # \dontrun{ # solve problems s <- stack(lapply(list(p1, p2, p3, p4, p5, p6), solve))
#> Gurobi Optimizer version 9.0.2 build v9.0.2rc0 (linux64) #> Optimize a model with 5 rows, 90 columns and 450 nonzeros #> Model fingerprint: 0xac25e0fe #> Variable types: 0 continuous, 90 integer (90 binary) #> Coefficient statistics: #> Matrix range [2e-01, 9e-01] #> Objective range [2e+02, 2e+02] #> Bounds range [1e+00, 1e+00] #> RHS range [6e+00, 2e+01] #> Found heuristic solution: objective 4544.4850483 #> Presolve time: 0.00s #> Presolved: 5 rows, 90 columns, 450 nonzeros #> Variable types: 0 continuous, 90 integer (90 binary) #> Presolved: 5 rows, 90 columns, 450 nonzeros #> #> #> Root relaxation: objective 3.899056e+03, 12 iterations, 0.00 seconds #> #> Nodes | Current Node | Objective Bounds | Work #> Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time #> #> 0 0 3899.05601 0 4 4544.48505 3899.05601 14.2% - 0s #> H 0 0 3988.8131278 3899.05601 2.25% - 0s #> #> Explored 1 nodes (12 simplex iterations) in 0.00 seconds #> Thread count was 1 (of 4 available processors) #> #> Solution count 2: 3988.81 4544.49 #> #> Optimal solution found (tolerance 1.00e-01) #> Best objective 3.988813127763e+03, best bound 3.899056011987e+03, gap 2.2502% #> Gurobi Optimizer version 9.0.2 build v9.0.2rc0 (linux64) #> Optimize a model with 5 rows, 90 columns and 450 nonzeros #> Model fingerprint: 0x09f3d4df #> Variable types: 0 continuous, 90 integer (90 binary) #> Coefficient statistics: #> Matrix range [2e-01, 9e-01] #> Objective range [2e+02, 2e+02] #> Bounds range [1e+00, 1e+00] #> RHS range [6e+00, 2e+01] #> Found heuristic solution: objective 4406.7211374 #> Presolve removed 0 rows and 10 columns #> Presolve time: 0.00s #> Presolved: 5 rows, 80 columns, 400 nonzeros #> Variable types: 0 continuous, 80 integer (80 binary) #> Presolved: 5 rows, 80 columns, 400 nonzeros #> #> #> Root relaxation: objective 4.008577e+03, 15 iterations, 0.00 seconds #> #> Nodes | Current Node | Objective Bounds | Work #> Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time #> #> 0 0 4008.57651 0 4 4406.72114 4008.57651 9.03% - 0s #> #> Explored 0 nodes (15 simplex iterations) in 0.00 seconds #> Thread count was 1 (of 4 available processors) #> #> Solution count 1: 4406.72 #> #> Optimal solution found (tolerance 1.00e-01) #> Best objective 4.406721137419e+03, best bound 4.008576513407e+03, gap 9.0349% #> Gurobi Optimizer version 9.0.2 build v9.0.2rc0 (linux64) #> Optimize a model with 5 rows, 90 columns and 450 nonzeros #> Model fingerprint: 0x9735ede9 #> Variable types: 0 continuous, 90 integer (90 binary) #> Coefficient statistics: #> Matrix range [2e-01, 9e-01] #> Objective range [2e+02, 2e+02] #> Bounds range [1e+00, 1e+00] #> RHS range [6e+00, 2e+01] #> Found heuristic solution: objective 4359.4041324 #> Presolve removed 0 rows and 10 columns #> Presolve time: 0.00s #> Presolved: 5 rows, 80 columns, 400 nonzeros #> Variable types: 0 continuous, 80 integer (80 binary) #> Presolved: 5 rows, 80 columns, 400 nonzeros #> #> #> Root relaxation: objective 3.905365e+03, 11 iterations, 0.00 seconds #> #> Nodes | Current Node | Objective Bounds | Work #> Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time #> #> 0 0 3905.36483 0 4 4359.40413 3905.36483 10.4% - 0s #> H 0 0 4002.9475856 3905.36483 2.44% - 0s #> #> Explored 1 nodes (11 simplex iterations) in 0.00 seconds #> Thread count was 1 (of 4 available processors) #> #> Solution count 2: 4002.95 4359.4 #> #> Optimal solution found (tolerance 1.00e-01) #> Best objective 4.002947585629e+03, best bound 3.905364830968e+03, gap 2.4378% #> Gurobi Optimizer version 9.0.2 build v9.0.2rc0 (linux64) #> Optimize a model with 95 rows, 90 columns and 828 nonzeros #> Model fingerprint: 0x9d8ce8b6 #> Variable types: 0 continuous, 90 integer (90 binary) #> Coefficient statistics: #> Matrix range [2e-01, 2e+00] #> Objective range [2e+02, 2e+02] #> Bounds range [1e+00, 1e+00] #> RHS range [6e+00, 2e+01] #> Found heuristic solution: objective 5019.7804112 #> Presolve removed 2 rows and 4 columns #> Presolve time: 0.00s #> Presolved: 93 rows, 86 columns, 798 nonzeros #> Variable types: 0 continuous, 86 integer (86 binary) #> Presolved: 93 rows, 86 columns, 798 nonzeros #> #> #> Root relaxation: objective 3.909128e+03, 43 iterations, 0.00 seconds #> #> Nodes | Current Node | Objective Bounds | Work #> Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time #> #> 0 0 3909.12764 0 13 5019.78041 3909.12764 22.1% - 0s #> H 0 0 4231.2130368 3909.12764 7.61% - 0s #> #> Explored 1 nodes (43 simplex iterations) in 0.00 seconds #> Thread count was 1 (of 4 available processors) #> #> Solution count 2: 4231.21 5019.78 #> #> Optimal solution found (tolerance 1.00e-01) #> Best objective 4.231213036789e+03, best bound 3.909127637600e+03, gap 7.6121% #> Gurobi Optimizer version 9.0.2 build v9.0.2rc0 (linux64) #> Optimize a model with 236 rows, 234 columns and 1202 nonzeros #> Model fingerprint: 0x6b9fa975 #> Variable types: 0 continuous, 234 integer (234 binary) #> Coefficient statistics: #> Matrix range [2e-01, 1e+00] #> Objective range [2e+02, 2e+02] #> Bounds range [1e+00, 1e+00] #> RHS range [1e+00, 2e+01] #> Presolve removed 12 rows and 13 columns #> Presolve time: 0.01s #> Presolved: 224 rows, 221 columns, 1022 nonzeros #> Variable types: 0 continuous, 221 integer (221 binary) #> Presolved: 224 rows, 221 columns, 1022 nonzeros #> #> #> Root relaxation: objective 3.947815e+03, 153 iterations, 0.00 seconds #> #> Nodes | Current Node | Objective Bounds | Work #> Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time #> #> 0 0 3947.81491 0 90 - 3947.81491 - - 0s #> 0 0 3952.98944 0 79 - 3952.98944 - - 0s #> 0 0 3969.70422 0 80 - 3969.70422 - - 0s #> 0 0 3972.97474 0 89 - 3972.97474 - - 0s #> 0 0 3982.34764 0 98 - 3982.34764 - - 0s #> 0 0 3982.41767 0 94 - 3982.41767 - - 0s #> 0 0 3984.42060 0 91 - 3984.42060 - - 0s #> 0 0 3984.42060 0 90 - 3984.42060 - - 0s #> H 0 0 4608.4138755 3984.42060 13.5% - 0s #> 0 2 3984.65223 0 90 4608.41388 3984.65223 13.5% - 0s #> H 27 21 4285.2176945 3985.13341 7.00% 16.2 0s #> #> Cutting planes: #> Gomory: 3 #> Clique: 1 #> Zero half: 4 #> #> Explored 28 nodes (834 simplex iterations) in 0.13 seconds #> Thread count was 1 (of 4 available processors) #> #> Solution count 2: 4285.22 4608.41 #> #> Optimal solution found (tolerance 1.00e-01) #> Best objective 4.285217694549e+03, best bound 3.985133414355e+03, gap 7.0028% #> Gurobi Optimizer version 9.0.2 build v9.0.2rc0 (linux64) #> Optimize a model with 1610 rows, 1260 columns and 5110 nonzeros #> Model fingerprint: 0xd8b45813 #> Variable types: 0 continuous, 1260 integer (1260 binary) #> Coefficient statistics: #> Matrix range [2e-01, 1e+00] #> Objective range [2e+02, 2e+02] #> Bounds range [1e+00, 1e+00] #> RHS range [1e+00, 2e+01] #> Presolve removed 138 rows and 139 columns #> Presolve time: 0.05s #> Presolved: 1472 rows, 1121 columns, 4310 nonzeros #> Variable types: 0 continuous, 1121 integer (1121 binary) #> Presolved: 1472 rows, 1121 columns, 4310 nonzeros #> #> #> Root relaxation: objective 3.947815e+03, 1355 iterations, 0.03 seconds #> #> Nodes | Current Node | Objective Bounds | Work #> Expl Unexpl | Obj Depth IntInf | Incumbent BestBd Gap | It/Node Time #> #> 0 0 3947.81491 0 484 - 3947.81491 - - 0s #> 0 0 3962.22255 0 506 - 3962.22255 - - 0s #> 0 0 3962.24024 0 521 - 3962.24024 - - 0s #> 0 0 3965.20129 0 512 - 3965.20129 - - 0s #> 0 0 3965.97496 0 566 - 3965.97496 - - 0s #> 0 0 3965.97649 0 565 - 3965.97649 - - 0s #> 0 0 3965.97649 0 567 - 3965.97649 - - 0s #> 0 0 3965.97649 0 569 - 3965.97649 - - 0s #> 0 0 3966.11290 0 569 - 3966.11290 - - 0s #> 0 0 3966.13666 0 595 - 3966.13666 - - 0s #> 0 0 3966.20628 0 599 - 3966.20628 - - 0s #> 0 0 3966.20628 0 596 - 3966.20628 - - 0s #> H 0 0 16261.364549 3966.20628 75.6% - 0s #> H 0 0 12303.647295 3966.20628 67.8% - 0s #> 0 2 3966.21298 0 596 12303.6473 3966.21298 67.8% - 0s #> H 60 59 4256.7194199 3966.68807 6.81% 78.9 1s #> #> Cutting planes: #> Gomory: 3 #> Zero half: 4 #> #> Explored 61 nodes (7758 simplex iterations) in 1.07 seconds #> Thread count was 1 (of 4 available processors) #> #> Solution count 3: 4256.72 12303.6 16261.4 #> #> Optimal solution found (tolerance 1.00e-01) #> Best objective 4.256719419865e+03, best bound 3.966688065920e+03, gap 6.8135%
# plot solutions plot(s, box = FALSE, axes = FALSE, nr = 2, main = c("minimal problem", "locked in", "locked out", "neighbor", "contiguity", "feature contiguity"))
# }