From prioritizr, prioriactions and prioripy¶
ls.prioritize builds the same optimization models as the R packages
prioritizr (8.0.6) and
prioriactions (0.5.0), row by row, and keeps their
vocabulary, so most scripts translate line by line. This page is the dictionary: what changes in the
syntax, the equivalent of every function, what to expect when you compare the results, and the
replacements for prioripy, the Python package ls.prioritize
grew out of. The ideas behind each function are in the course part
Conservation priorities; the full reference is the
Spatial prioritization API page.
What changes, what stays¶
| prioritizr / prioriactions (R) | ls.prioritize |
|
|---|---|---|
| Building a problem | pipes: problem(...) %>% add_...() |
method chains: P.problem(...).add_...() |
| Order of the calls | targets are resolved when the problem is built | any order: everything is resolved by compile() and solve() |
| A call changes the problem? | returns a new problem | returns a new problem (a Problem is immutable) |
| Rasters, polygons, tables | terra SpatRaster, sf, data.frame |
xarray.DataArray (ls.load_raster), GeoDataFrame, pandas.DataFrame |
| Features | layers or columns | bands of a stack, a list of rasters, or columns; always by name |
| Default solver | the best one installed (Gurobi, CPLEX, CBC, HiGHS...) | HiGHS, built into Landschaft (nothing to install) |
| Threads | threads = 1 |
n_threads: all cores but one by default |
Result of solve |
the input's class with a solution_1 layer or column |
a Solution: selection (raster or table), values, coverage, cost, objective, gap, bound, status, seconds |
| Evaluations | tibble |
pandas.DataFrame, the same columns |
| Plots | plot(s) |
ls.plot(s) |
A script, side by side¶
library(prioritizr)
library(terra)
cost <- rast("cost.tif")
features <- rast("features.tif")
protected <- rast("protected.tif")
p <- problem(cost, features) %>%
add_min_set_objective() %>%
add_relative_targets(0.3) %>%
add_boundary_penalties(penalty = 0.003, edge_factor = 0.5) %>%
add_locked_in_constraints(protected) %>%
add_binary_decisions() %>%
add_highs_solver(gap = 0.01)
s <- solve(p)
attr(s, "status"); attr(s, "objective")
eval_target_coverage_summary(p, s)
eval_cost_summary(p, s)
writeRaster(s, "solution.tif")
import landschaft as ls
P = ls.prioritize
cost = ls.load_raster(P.example_data("cost"))
features = ls.load_raster(P.example_data("features"))
protected = ls.load_raster(P.example_data("protected"))
p = (P.problem(cost, features)
.add_min_set_objective()
.add_relative_targets(0.3)
.add_boundary_penalties(penalty=0.003, edge_factor=0.5)
.add_locked_in_constraints(protected)
.add_binary_decisions()
.add_highs_solver(gap=0.01))
s = p.solve()
s.status, s.objective
P.eval_target_coverage_summary(p, s)
P.eval_cost_summary(p, s)
ls.write_raster(s.selection, "solution.tif")
The importance of the selected units works the same way:
ranks, steps = P.eval_rank_importance(p, s, n=4) # prioritizr: eval_rank_importance(p, s, n = 4)
ls.plot(ranks)
prioritizr, function by function¶
Problems and data¶
| prioritizr | ls.prioritize |
|---|---|
problem(cost_raster, features) |
P.problem(cost_raster, features) |
problem(sf, features, cost_column = "cost") |
P.problem(gdf, features, cost_column="cost") (features: rasters summed over the polygons as exactextractr does, or column names) |
problem(pu, features, rij = rij, cost_column = "cost") |
P.problem(pu, features, rij=rij, cost_column="cost") (Marxan-style tables: pu with id, features with id, name, rij with pu, species, amount) |
feature_names(p), number_of_features(p) |
p.units.feature_names, len(p.units.feature_names) |
number_of_planning_units(p) |
p.units.n |
compile(p) |
p.compile(): A, obj, rhs, sense, lb, ub, vtype, modelsense, row_ids, col_ids (R's o$A(), o$obj(), ...) |
get_sim_pu_raster(), get_sim_features() |
P.example_data("cost"), P.example_data("features") (Serra Verde) |
| Planning units as hexagons | P.h3_units(cost, resolution) |
Objectives¶
| prioritizr | ls.prioritize |
|---|---|
add_min_set_objective() |
.add_min_set_objective() |
add_min_shortfall_objective(budget) |
.add_min_shortfall_objective(budget) |
add_min_largest_shortfall_objective(budget) |
.add_min_largest_shortfall_objective(budget) |
add_max_utility_objective(budget) (9: add_max_wtd_sum_objective) |
.add_max_utility_objective(budget), or .add_max_wtd_sum_objective(budget) |
add_max_features_objective(budget) (9: add_max_n_targets_met_objective) |
.add_max_features_objective(budget), or .add_max_n_targets_met_objective(budget) |
add_max_cover_objective(budget) |
.add_max_cover_objective(budget) |
add_max_phylo_div_objective(budget, tree) |
.add_max_phylo_div_objective(budget, tree) (an ls.bio tree or a Newick string) |
add_max_phylo_end_objective(budget, tree) |
.add_max_phylo_end_objective(budget, tree) |
add_min_penalties_objective(budget) |
.add_min_penalties_objective(budget) |
| — | .add_min_extinction_risk_objective(budget, z=0.25) (species-area extinction risk) |
Targets and weights¶
| prioritizr | ls.prioritize |
|---|---|
add_relative_targets(0.3) |
.add_relative_targets(0.3) (one value or one per feature) |
add_absolute_targets(x) |
.add_absolute_targets(x) |
add_loglinear_targets(...) |
.add_loglinear_targets(...) (the same arguments) |
add_manual_targets(df) |
.add_manual_targets(df) (feature, type, sense, target) |
add_auto_targets(), add_group_targets(), spec_*_targets() (8.1) |
compute the targets in Python and pass them to .add_absolute_targets() or .add_relative_targets() |
| — | .add_subregional_targets(regions, targets): targets within regions |
add_feature_weights(w) |
.add_feature_weights(w) |
Constraints¶
| prioritizr | ls.prioritize |
|---|---|
add_locked_in_constraints(x) |
.add_locked_in_constraints(x) (a raster with 1, a column name, booleans or indices) |
add_locked_out_constraints(x) |
.add_locked_out_constraints(x) |
add_manual_locked_constraints(data) |
.add_manual_locked_constraints(data) (the same table: pu, status), or status= as a number, raster, column or values |
add_manual_bounded_constraints(data) |
.add_manual_bounded_constraints(data) (pu, lower, upper), or lower= / upper= |
add_linear_constraints(threshold, sense, data) |
.add_linear_constraints(threshold, sense, data) |
add_cost_constraints() (9) |
.add_linear_constraints(threshold, "<=", cost) |
add_contiguity_constraints(data) |
.add_contiguity_constraints(data) (an exact model: see below) |
add_feature_contiguity_constraints(data) |
.add_feature_contiguity_constraints(data) (exact) |
add_neighbors_constraints(k, clamp) (newer: add_neighbor_constraints) |
.add_neighbors_constraints(k, clamp), or .add_neighbor_constraints(k, clamp) |
add_corridor_constraints() (removed from prioritizr) |
.add_corridor_constraints(terminals, resistance, penalty): a different, working formulation (flows between terminals) |
Penalties¶
| prioritizr | ls.prioritize |
|---|---|
add_boundary_penalties(penalty, edge_factor, data) |
.add_boundary_penalties(penalty, edge_factor, data=None) |
add_connectivity_penalties(penalty, data = m) |
.add_connectivity_penalties(penalty, m) |
add_asym_connectivity_penalties(penalty, data = m) |
.add_asym_connectivity_penalties(penalty, m) |
add_linear_penalties(penalty, data) |
.add_linear_penalties(penalty, data) |
add_cost_penalties() (9) |
.add_linear_penalties(penalty, cost) |
Decisions, solvers and portfolios¶
| prioritizr | ls.prioritize |
|---|---|
add_binary_decisions() |
.add_binary_decisions() |
add_proportion_decisions() |
.add_proportion_decisions() |
add_semicontinuous_decisions(upper_limit) |
.add_semicontinuous_decisions(upper_limit) |
add_highs_solver(gap, time_limit, threads, presolve, verbose) |
.add_highs_solver(gap, time_limit, n_threads, presolve, verbose) |
add_gurobi_solver(gap, time_limit, threads, verbose) |
.add_gurobi_solver(gap, time_limit, n_threads, verbose) (needs gurobipy) |
add_default_solver(), add_cbc_solver(), add_cplex_solver(), add_lpsymphony_solver(), add_rsymphony_solver() |
.add_highs_solver() |
| — | .add_anneal_solver(...): Marxan's simulated annealing on the same model |
add_default_portfolio(), add_single_portfolio() |
the default |
add_cuts_portfolio(n) |
.add_cuts_portfolio(n) |
add_shuffle_portfolio(n, remove_duplicates) |
.add_shuffle_portfolio(n, remove_duplicates) |
add_top_portfolio(n) |
.add_top_portfolio(n) (also on HiGHS) |
add_gap_portfolio(n, pool_gap), add_extra_portfolio(), add_pool_portfolio() |
.add_gap_portfolio(n, pool_gap) (also on HiGHS) |
solve(p) |
p.solve(); p.solve(start=...) from a solution or a Zonation ranking |
attr(s, "objective"), "status", "gap", "runtime" |
s.objective, s.status, s.gap, s.seconds |
eval_objective_summary(p, s) (9) |
s.objective |
A portfolio solves to a Portfolio: selection (a
band or a column per solution, named solution_1, solution_2... as in prioritizr), summary and
frequency (the share of the solutions that select every unit).
Evaluation¶
Every eval_* function has the same name and arguments: P.eval_n_summary(p, s),
eval_cost_summary, eval_feature_representation_summary, eval_target_coverage_summary,
eval_boundary_summary, eval_connectivity_summary, eval_asym_connectivity_summary,
eval_ferrier_importance, eval_rank_importance, eval_rare_richness_importance and
eval_replacement_importance (in parallel). The old names map to them: replacement_cost →
eval_replacement_importance, rarity_weighted_richness → eval_rare_richness_importance,
ferrier_score → eval_ferrier_importance, feature_representation →
eval_feature_representation_summary.
Beyond prioritizr: P.eval_extinction_risk, P.eval_landscape_metrics and P.eval_mspa (the
solution's pattern), P.compare_zonation (a Zonation ranking cut at the solution's cost) and
P.report(p, s), everything in one object that ls.plot draws and .save("report.html") writes.
Spatial data and calibration¶
| prioritizr | ls.prioritize |
|---|---|
boundary_matrix(x) |
P.boundary_matrix(x) |
adjacency_matrix(x, directions) |
P.adjacency_matrix(x, directions) |
connectivity_matrix(x, y) |
P.connectivity_matrix(x, y) |
proximity_matrix(x, distance) |
P.proximity_matrix(x, distance) |
rescale_matrix(m) |
m / m.max() |
calibrate_cohon_penalty(p) |
P.cohon_penalty(p) |
| the blended approach of the calibration vignette | P.calibrate_penalty(p, "boundary", values=...) |
the hierarchical approach of the calibration vignette, multi_problem() with add_hier_approach() (9) |
P.calibrate_budget(p, "boundary", ...) |
| a loop over budgets | P.pareto_front(p, n=10) |
| any other parameter | P.calibrate(make, values, criterion), then .best("knee") or .best("topsis") |
Management zones¶
| prioritizr | ls.prioritize |
|---|---|
problem(costs, zones(f_a, f_b, zone_names = c("a", "b"))) |
P.problem({"a": cost_a, "b": cost_b}, features={"a": f_a, "b": f_b}) |
zones(f, f * 0.5, ...) (the same features scaled per zone) |
P.problem({"a": cost_a, "b": cost_b}, f, contribution={"b": 0.5}) (a number, one per feature, or a raster) |
problem(x, zones(c("f1", ...), c("g1", ...)), cost_column = c("ca", "cb")) |
P.problem(x, features={"a": ["f1", ...], "b": ["g1", ...]}, cost_column={"a": "ca", "b": "cb"}) |
problem(x, spec, rij, cost_column, zones = z) (rij$zone) |
P.problem(x, spec, rij=rij, zones=z, cost_column=[...]) |
add_relative_targets(matrix(...)) (features x zones) |
the same matrix, or add_relative_targets(0.3) (summed over the zones) and add_relative_targets(0.1, zone="a") |
add_manual_targets() with zone = list(c("a", "b")) |
the same table (a zone or a list per row; no column: every zone) |
add_mandatory_allocation_constraints() |
p.add_mandatory_allocation_constraints() |
add_locked_in_constraints(matrix / stack) |
p.add_locked_in_constraints({"a": raster_a, ...}) (or the stack, or P.binary_stack(map)) |
budgets c(b_a, b_b) |
[b_a, b_b] or {"a": b_a, "b": b_b} |
add_feature_weights(matrix(...)) |
the same matrix (or one weight per feature, the same in every zone) |
add_boundary_penalties(p, edge_factor, zones = m) |
p.add_boundary_penalties(p, edge_factor=[...], zones=m) ("same" is the identity) |
add_connectivity_penalties(p, zones = m, data), add_asym_connectivity_penalties |
the same with zones=m |
add_linear_penalties(c(...), data) |
p.add_linear_penalties([...], {"a": data_a, ...}) |
add_neighbor_constraints(k = c(...), zones = m), add_contiguity_constraints(zones = m) |
the same with k=[...] and zones=m |
category_layer(s), binary_stack(x) |
P.category_layer(s), P.binary_stack(x); a solution's zones is already the map |
eval_*_summary(p, s) with zones |
the same functions: a row overall and one per zone |
Not with zones: arrays of connectivity or neighbours by pairs of zones (4-D), feature contiguity and the corridors (an extension of Landschaft), Ferrier and rarity-weighted importance (as in prioritizr).
Not available¶
Neighbour penalties (add_neighbor_penalties()), the
weighted-sum and reference-point approaches of multi_problem() (9), presolve_check() and the target
methods of 8.1 (spec_*_targets()). Open an issue if you need one of them.
What to expect when you compare the results¶
- The models are prioritizr 8.0.6's.
p.compile()gives the same matrix, objective and bounds as R'scompile(p), row by row (the test suite checks every objective, target, constraint, penalty and decision against it), with one exception below. - Contiguity is exact here. prioritizr's contiguity constraints (and feature contiguity) build a tree whose edges always run from a unit to one of a lower index. That misses every patch in which a unit has no selected neighbour of a higher index: three units in a line with the middle one first have no feasible patch at all, and on larger problems the "optimal" patch can cost more than the best one. Landschaft uses an exact model (a spanning arborescence with a flow), so its patches are as cheap or cheaper, and a problem prioritizr calls infeasible may have a solution here. The restricted model is still used, as a quick first patch.
- Zones: targets summed over the zones are shares of the features' totals. With the easy form
(
contribution=),add_relative_targets(0.3)asks for 30% of every feature's total, its amounts in every zone counted by the zone's contribution: prioritizr's manual absolute target with the list of every zone. A relative target of one zone is a share of the feature's total in that zone, as in prioritizr; with every zone's own features (aszones()), a target over several zones is a share of the sum of their totals, as in prioritizr. - Three prioritizr bugs with zones are fixed here. Manual bounds or locks no longer open a zone where a unit has no cost (prioritizr gives it cost 0 there); the default adjacency (neighbour and contiguity constraints) takes the cells with a cost in any zone (prioritizr's takes those with a cost in every zone, so a unit missing from one zone has no neighbours); linear penalties keep the other zones' when one zone's is 0 (prioritizr drops them all).
- prioritizr 9 changed three things. It rescales the boundary data it computes so that their largest
value is 1, so a penalty from a prioritizr 9 script corresponds here to that penalty divided by
P.boundary_matrix(cost).max(). It dropped the small cost term that breaks ties in the maximum utility, maximum features and phylogenetic objectives. And it renamed two objectives (both names work here). - Optimal is not unique. Two solvers, or two versions of one, can return different selections with the same objective. Compare the objective (and the gap and bound), not the cells.
- The gap means the same.
gap=0.1stops within 10 % of the optimum, as in prioritizr; for a final plan use a small gap. - Faster, not different. Landschaft's own engines (covering, cuts, closure) reach the solutions faster than the solver alone and prove the same bounds; the benchmarks list the times.
- Top fractions count cells by position. prioripy's landscape identification and comparison take every unit at or above a quantile of the surface, so ties can add units. Landschaft follows Zonation: the cells are ranked by position (ties: the earlier cell in row order ranks lower) and the top fraction is the cells ranked at or above 1 − fraction, which on a Zonation ranking gives Zonation's own areas. The areas are 8-connected by default (prioripy: 4) and keep Zonation's numbers.
To check a migrated analysis, export R's compiled model and compare:
import numpy as np
import pandas as pd
m = p.compile()
r_obj = pd.read_csv("obj.csv")["x"].to_numpy() # R: write.csv(data.frame(x = o$obj()), "obj.csv")
np.allclose(m.obj, r_obj), m.A.shape # R: dim(o$A())
prioriactions¶
| prioriactions | ls.prioritize |
|---|---|
inputData(pu, features, dist_features, threats, dist_threats, sensitivity, boundary) |
P.actions_data(pu, features, dist_features, threats, dist_threats, sensitivity, boundary) (the same tables and columns) |
| — | P.actions_raster_data(monitoring_cost, features, threats, action_cost, ...): the same from rasters |
getPotentialBenefit(d) |
d.potential_benefit() |
problem(d, model_type = "minimizeCosts", budget, blm, curve, segments) |
d.problem(model="minimizeCosts", budget=..., blm=..., curve=..., segments=...) |
getModelInfo(m) |
m.compile() |
solve(m, solver = "gurobi", gap_limit, time_limit, cores, verbose) |
m.add_gurobi_solver(gap, time_limit, n_threads, verbose).solve(), or add_highs_solver (the default) |
getActions(s), getActions(s, format = "large") |
s.action_summary(), s.action_summary(format="long") |
getCost(s) |
s.cost() |
getSolutionBenefit(s), getSolutionBenefit(s, type = "local") |
s.benefit(), s.local_benefit |
getConnectivityPenalty(s) |
s.connectivity_penalty() |
s$data$objval, s$data$gap, s$data$sol |
s.objective, s.gap, s.x |
| — | portfolios (add_cuts_portfolio and the others), add_directional_dependencies(flow), s.maps() with raster inputs |
The example of prioriactions's documentation, in both:
library(prioriactions)
d <- inputData(pu = sim_pu_data, features = sim_features_data,
dist_features = sim_dist_features_data, threats = sim_threats_data,
dist_threats = sim_dist_threats_data, sensitivity = sim_sensitivity_data,
boundary = sim_boundary_data)
m <- problem(d, model_type = "minimizeCosts")
s <- solve(m, solver = "gurobi", gap_limit = 0.01, output_file = FALSE)
getActions(s)
import pandas as pd
pu = pd.DataFrame({"id": [1, 2, 3, 4], "monitoring_cost": [2.0, 1.0, 3.0, 1.0]})
feats = pd.DataFrame({"id": [1, 2], "target_recovery": [1.0, 0.5]})
dist_features = pd.DataFrame({"pu": [1, 2, 3, 3, 4], "feature": [1, 1, 1, 2, 2], "amount": 1.0})
threats = pd.DataFrame({"id": [1]})
dist_threats = pd.DataFrame({"pu": [1, 2, 3, 4], "threat": 1, "amount": 1.0,
"action_cost": [1.0, 4.0, 2.0, 1.0]})
d = P.actions_data(pu, feats, dist_features, threats, dist_threats)
m = d.problem(model="minimizeCosts")
sa = m.add_highs_solver(gap=0.01).solve()
sa.action_summary()
prioripy¶
prioripy 0.11 was the starting point of ls.prioritize's design. The core was rewritten to build
prioritizr's models exactly, so some results change (see the next section).
| prioripy | ls.prioritize |
|---|---|
problem("pu.tif", ["sp1.tif", ...], feature_names) |
P.problem(ls.load_raster("pu.tif"), ls.load_raster(["sp1.tif", ...])) (names from the files or the bands) |
add_min_set_objective(), add_min_shortfall_objective(budget), add_min_largest_shortfall_objective(budget) |
the same |
add_max_utility_objective(budget), add_max_wtd_sum_objective(budget) |
.add_max_utility_objective(budget) |
add_max_cover_objective(budget) (the most targets met) |
.add_max_features_objective(budget); add_max_cover_objective is prioritizr's (the most features held at all) |
add_relative_targets, add_absolute_targets |
the same |
add_subregional_targets(...) |
.add_subregional_targets(regions, targets) |
add_feature_weights(default_weight, specific_weights, csv_path) |
.add_feature_weights(weights) (one per feature, in the features' order) |
add_condition_layer(condition, feature_indices) |
features * condition before P.problem, or P.zonation_features(features, condition=...) |
apply_feature_smoothing(i, radius_cells) |
P.zonation_features(features, connectivity=[P.Kernel("gaussian", radius), ...]) |
add_extra_variable(data, weight) |
another band of features with its weight in .add_feature_weights() |
add_locked_in_constraints, add_locked_out_constraints, add_contiguity_constraints |
the same |
add_linear_constraints(sense, threshold, data) |
.add_linear_constraints(threshold, sense, data) (prioritizr's order) |
add_neighbor_constraints(k) |
.add_neighbor_constraints(k) |
add_corridors(terminals, resistance) |
.add_corridor_constraints(terminals, resistance, penalty) |
add_boundary_penalties, add_connectivity_penalties, add_linear_penalties |
the same (the connectivity penalties now work in every objective) |
add_neighbor_penalties(penalty, data) |
not available |
add_continuous_bounds(upper, lower) |
.add_proportion_decisions().add_manual_bounded_constraints(lower=lower, upper=upper) |
add_solver("auto"), add_highs_solver(gap, time_limit), add_gurobi_solver(...) |
.add_highs_solver(gap, time_limit), .add_gurobi_solver(...) |
add_single_portfolio, add_top_portfolio, add_cuts_portfolio, add_gap_portfolio, add_shuffle_portfolio, add_extra_portfolio |
the same (add_extra_portfolio → add_gap_portfolio), all on HiGHS as well |
add_actions(...), add_threats(...), add_sensitivity(...), add_multi_action_boundary_penalties(...) |
P.actions_raster_data(monitoring_cost, features, threats, action_cost, sensitivity=..., blm_actions=...) |
add_directional_dependencies(df_flow, penalty_multiplier) |
ActionsProblem.add_directional_dependencies(flow, penalty) (source_pu, target_pu, strength) |
solve_iteratively(...) |
P.iterative_solve(p, update, steps) |
calibrate_penalty(...) |
P.calibrate_penalty(p, ...) |
calibrate_feature_weight(...) |
P.calibrate(lambda w: ..., values, criterion) |
generate_pareto_front(...) |
P.pareto_front(p, ...) |
eval_target_coverage_summary, eval_rank_importance |
the same |
eval_ferrier_importance (a simplified ratio) |
P.eval_ferrier_importance: Ferrier et al.'s index, as prioritizr |
eval_irreplaceability(prob, portfolio) |
p.add_cuts_portfolio(n).solve().frequency (flexibility: 1 − frequency) |
eval_marginal_loss(prob, s) |
P.eval_replacement_importance(p, s) (the objective's loss, by re-solving) |
eval_landscape_identification(prob, importance, top_fraction, min_size, connectivity, merge_distance) |
P.eval_landscape_identification(surface, top_fraction, min_size=, connectivity=, merge_distance=, problem=p) (8-connected by default, as Zonation; the top fraction by Zonation's rule, see below) |
eval_landscape_comparison(prob, a, b, thresholds) |
P.eval_landscape_comparison(a, b, fractions) |
eval_roi_vulnerability(...) |
the features' sum over the cost, in numpy (below) |
eval_proxirr(...) |
P.eval_proxirr(p, triage), or P.eval_proxirr_marxan(pu, spec, puvspr) for Marxan's tables (the CRAN package proxirr's results, bit for bit) |
calc_extinction_risk_features(...) |
.add_min_extinction_risk_objective(budget, z) and P.eval_extinction_risk(p, s, z) |
prob.write_raster(path) |
ls.write_raster(s.selection, path) or s.save(folder) |
prob.plot(), prob.explore() |
ls.plot(s) |
prob.generate_report(path), generate_calibration_report(...) |
P.report(p, s).save("report.html"), ls.plot(tradeoffs) |
Two of the prioripy measures in a few lines:
import numpy as np
p0 = P.problem(cost, features).add_min_set_objective().add_relative_targets(0.2).add_binary_decisions()
s0 = p0.solve()
amount = features.sum("band").values # every cell's total amount of the features
roi = np.where(s0.selection.values == 1, amount / cost.values, 0.0) # return on investment
frequency = p0.add_shuffle_portfolio(4, seed=1).solve().frequency # selection frequency
What changes from prioripy¶
- One model for every solver. prioripy built different models for Gurobi and HiGHS (penalties scaled by 1e-5 on one of them), so its results depended on what was installed; here the solver only solves.
- The order of the calls does not matter: relative targets, conditions and weights are resolved when the problem is solved. Values per feature follow the features' order and tables name the features; there is no 0- or 1-based feature index to guess.
max_coveris prioritizr's. prioripy'smax_cover(the most targets met) isadd_max_features_objectivehere.- Errors are raised. prioripy swallowed failed steps in the calibrations and the rank importance; here a failed step stops with its error.
- Ferrier's index is the published one, and the replacement importance exists.
See also¶
- Spatial prioritization: the API reference.
- Optimized conservation plans: a complete plan, step by step.
- 12.10 The planning process: where the software fits.