Systematic conservation prioritization in R
problem()
objects. This
new default portfolio -- which can be manually specified using
add_default_portfolio()
-- involves simply generating a single solution.
The reason why this new default portfolio method was chosen was because
planning problems that contain insufficient data (e.g., feature and cost
data) to identify meaningful priorities can sometimes result in solutions
containing strange spatial artifacts (e.g., lines or bands of selected
planning units, see #205 and #268). Since the presence of these spatial
artifacts can indicate an under-specified problem and shuffling
optimization problems can suppress them, we have
decided to update the default portfolio so that it does not shuffle problems.
If users wish to prevent spatial artifacts from appearing in solutions, then
spatial penalties (e.g., add_boundary_penalties()
), spatial constraints
(e.g., add_neighbor_constraints()
), or shuffle portfolios
(e.g., add_shuffle_portfolio(number_solutions = 1)
) can be used.add_default_portfolio()
function for specifying the default
behavior for generating a solution (see Notice above for further details).solve()
so that it provides information on the optimality of
solutions (#323). For example, you might specify a 10% optimality gap
for the optimization process (e.g., using add_highs_solver(gap = 0.1)
), and
this might produce a solution that is at least 7% from optimality. The
resulting output from solve()
will now provide this information about
the solution (i.e., the 7% from optimality), and can be accessed
using the gap
attribute (e.g., attr(x, "gap")
, where x
is the output
from solve()
). Note that this information is currently only available when
using the Gurobi or HiGHS solvers.add_linear_constraints()
and add_linear_penalties()
that
resulted in an incorrect error message being shown (#324).add_shuffle_portfolio()
that prevented solvers from using a
pre-specified starting solution (per the start
parameter) correctly.
Please note that this bug did not result in incorrect solutions, it only
meant that any pre-specified starting solutions were not used properly.add_cplex_solver()
that caused solutions to not provide
runtime information for the optimization process.add_shuffle_portfolio()
so that optimization problems are
randomly shuffled when a single solution is requested. This update should
help prevent "strange" solutions that contain long horizontal lines/bands of
planning units (#205, #268).add_contiguity_constraints()
and
add_feature_contiguity_constraints()
to be compatible with updates to
the igraph package.write_problem()
so that it can use the gurobi package to write
problems (if desired). This substantially reduces run time, because writing
problems using the Rsymphony packages also requires solving them.presolve_check()
to throw warning if a problem has a single feature
(#309). Thanks to Sandra Neubert (@sandra-neubert) for code contribution.print()
and summary()
for problem()
objects so that all
text is printed at once (rather than sequentially).write_problem()
so that it works as expected (#312).problem()
, add_linear_constraints()
, add_linear_penalties()
,
add_locked_in_constraints()
, add_locked_out_constraints()
,
adjacency_matrix()
, binary_stack()
, category_layer()
,
connectivity_matrix()
,fast_extract()
, intersecting_units()
,
proximity_matrix()
, rij_matrix()
, simulate_data()
,
simulate_species()
, simulate_cost()
, and zones()
and other functions so
that they will throw an error if a categorical terra::rast()
object is
provided as an argument (#313). This is because categorical rasters are not
supported. Thanks to Martin Jung (@Martin-Jung) for bug report.problem()
not throwing multiple warnings with unusual data
(e.g., given cost and feature data with negative values, previously
only a single warning about negative costs would be thrown).
Thanks to Sandra Neubert (@sandra-neubert) for bug report.problem()
to be more memory efficient when using a sparse matrix
(dgCMatrix
) argument for the rij_matrix
parameter.Caused by error
instead of Caused by NULL
.add_locked_in_constraints()
and add_locked_in_constraints()
error
messages when supplying locked_in
and locked_out
objects
that do not spatially intersect with the planning units.scales::rescale()
to rescale such data.
However, we now realize that this approach can produce inconsistencies for
boundary length data (e.g., the total perimeter of a planning unit might not
necessarily equal the sum of the edge lengths). In some cases, these
inconsistencies can cause solutions generated with high boundary
penalties (i.e., using add_boundary_penalties()
with a high penalty
value) to contain a large reserve (i.e., a spatial cluster of selected of
planning units) with a single unselected planning unit in the middle of the
reserve. In the the worst case, these inconsistencies produce a situation
where increasing boundary penalties (i.e., generating multiple solutions with
add_boundary_penalties()
and increasing penalty
values)
does not alter the spatial configuration of solutions. Although use of
scales::rescale()
did not produce such behavior prior to version 8.0.0,
changes to the output format for boundary_matrix()
in subsequent versions
now mean that scales::rescale()
can cause these issues. We now recommend
using the new rescale_matrix()
function to rescale boundary length data to
avoid numerical issues, whilst also avoid such inconsistencies.rescale_matrix()
function to help with rescaling boundary length
(e.g., generated using boundary_matrix()
) and connectivity
(e.g., generated using connectivity_matrix()
) data so avoid
numerical issues during optimization (#297).add_neighbors_constraints()
so that it has an additional
clamp
argument so the minimum number of neighbors permitted for
each planning unit in the solution is clamped to the number of neighbors that
each planning unit has. For example, if a planning unit has 2 neighbors,
k = 3
, and clamp = FALSE
, then the planning unit could not
ever be selected in the solution. However, if clamp = TRUE
, then
the planning unit could potentially be selected in the solution if both of
its 2 neighbors were also selected.rescale_matrix()
function
instead of the scales::rescale()
function for rescaling boundary
length and connectivity data (#297).print()
and summary()
methods for problem()
objects
so that they will now better describe situations when the planning cost
data all contain a constant value (e.g., all costs equal to 1).problem()
that prevents features
being supplied as
a data.frame
that contains feature names stored as a factor
(#295).rij_matrix()
so that it works when none of the raster layers being
processed fit into memory (#290).get_sim_pu_raster()
, get_sim_locked_in_raster()
,
get_sim_locked_out_raster()
, get_sim_zones_pu_raster()
,
get_sim_features()
, get_sim_zones_features()
).add_manual_locked_constraints()
and
add_manual_bounded_constraints()
so that the indices in the
specified in the argument data$pu
should consistently refer to the total
units. In other words, the indices in data$pu
should refer to the row
numbers (for planning units in sf
or data.frame
format) or cell numbers
(for planning units in Raster
or SpatRaster
format) of the planning units
that should be locked.problem()
so that it will throw a meaningful error message if the
user accidentally specifies the geometry column for sf
planning unit data
as a feature.solve.ConservationProblem()
so that it can be called directly (#283).problem()
so that an error will be thrown if argument to features
contains only missing (NA
) values (e.g., an sf object is supplied that
has NA
values in all rows for a feature's column).raster::stack()
and sp::SpatialPolyonsDataFrame()
)
are still supported, the prioritizr package will now throw deprecation
warnings. Since support for the sp and raster package classes
will be fully deprecated and removed in a later version this year, we
recommend updating code to use the sf and terra packages.problem()
objects can now contain many more
constraints and penalties. Note that any problem()
objects
that were produced using earlier versions of the package are no longer
compatible.library(sf)
).get_sim_pu_raster()
,
get_sim_pu_polygons()
, get_sim_pu_lines()
, get_sim_pu_points()
,,
get_sim_locked_in_raster()
, get_sim_locked_out_raster()
,
get_sim_zones_pu_raster()
, get_sim_zones_pu_polygons()
,
get_sim_phylogeny()
, get_sim_features()
, get_sim_zones_features()
).
These functions now return sf::st_sf()
,
terra::rast()
, ape::read.tree()
and zones()
objects.
Note that these functions are provided because data(...)
cannot be
used with terra::rast()
objects. See ?data
for more information.boundary_matrix()
output format has been updated. This means that
users will not be able to use boundary data generated using previous
versions of the package.add_lpsymphony_solver()
now throws an error, instead of a warning,
if an old version of the lpsymphony R package is installed that is known
to produce incorrect results.marxan_boundary_data_to_matrix()
function is no longer compatible
with boundary data for multiple zones.distribute_load()
function has been deprecated, because it is no
longer used. For equivalent functionality, See parallel::splitIndices()
.new_optimization_problem()
and predefined_optimization_problem()
functions have been superseded by the new optimization_problem()
function.is.Waiver()
, add_default_decisions()
new_id()
, is.Id()
, print.Id()
, pproto()
.print()
function for problem()
, optimization_problem()
, and
zones()
objects has been updated to provide more information.summary()
function to provide extensive detail on problem()
objects."bad error message"
!add_feature_weights()
when applied to problems with
an add_max_phylo_div_objective()
or add_max_phylo_end_objectve()
.
Specifically, the bug meant that weights weren't being applied to
problems with these particular objectives.add_gurobi_solver()
documentation for opening vignette.add_extra_portfolio()
) default to generating 10 solutions.solve()
function will now output tibble::tibble()
objects
(instead of data.frame()
objects), when the planning unit data are
tibble::tibble()
objects.boundary_matrix()
function now uses terra::sharedPaths()
for
calculations, providing greater performance (#257).eval_ferrier_importance()
function can now be used with
any objective function that uses targets and a single zone.add_shuffle_portfolio()
and eval_replacement_importance()
functions.add_cbc_solver()
to throw a segfault when solving a problem wherein the rij_matrix(x)
has a zero amount for the last feature in the last planning unit (#247).simulate_data()
, simulate_cost()
and simulate_species()
functions to improve performance using the fields package.boundary_matrix()
to use STR query trees by default.boundary_matrix()
to use the geos package (#218).presolve_check()
function to (i) reduce chances of it incorrectly throwing an error when the input data won't actually cause any issues, and (ii) provide recommendations for addressing issues.add_min_largest_shortfall_objective()
so that examples complete in a shorter period of time.x
that are numeric
or matrix
format, (ii) x
that contain missing (NA
) values, and (iii) rij_matrix
that are in dgCMatrix
format. This bug only occurred when all three of these specific conditions were met. When it occurred, the bug caused planning units with NA
cost values to receive very high cost values (e.g., 1e+300). This bug meant that when attempting to solve the problem, the presolve checks (per presolve_check()
) would throw an error complaining about very high cost values (#236).add_locked_in_constraints()
and add_locked_out_constraints()
to ensure that a meaningful error message is provided when no planing units are locked (#234).presolve_check()
so that it does not throw a meaningless warning when the mathematical objective function only contains zeros.presolve_check()
to help reduce chances of mis-attributing high connectivity/boundary values due to planning unit costs.add_connectivity_penalties()
function and documentation so that it is designed specifically for symmetric connectivity data.add_asym_connectivity_penalties()
function that is designed specifically for asymmetric connectivity data. This function has been created to help ensure that asymmetric connectivity data are handled correctly. For instance, using asymmetric connectivity data with add_connectivity_penalties()
function in previous versions of the package sometimes resulted in the data being incorrectly treated as symmetric data. Additionally, this function uses an updated mathematical formulation for handling asymmetric connectivity so that it provides similar results to the Marxan software (#323).marxan_problem()
function so that it can be used with asymmetric connectivity data. This is now possible because there are dedicated functions for symmetric and asymmetric connectivity.zones
parameter of the add_connectivity_penalties()
function.eval_ferrier_importance()
(#220). Although this function is now recommended for general use, the documentation contained an outdated warning and so the warning has now been removed.eval_n_summary()
function now returns a table with the column name "n"
(instead of "cost"
) for the number of selected planning units (#219).marxan_problem()
for importing Marxan data files.sim_pu_sf
and sim_pu_zones_sf
data given class updates to the sf package (compatible with version 1.0.3+).write_problem()
function.This release contains version 3.0.4 of the prioritizr R package. It is significant because this version is the most the most up-to-date and best-working version of the package before it was over-hauled to manage problems with multiple management zones.