spopt.locate.PDispersion¶
- class spopt.locate.PDispersion(name: str, problem: LpProblem, p_facilities: int)[source]¶
Implement the \(p\)-dispersion optimization model and solve it [Kub87]. The \(p\)-dispersion problem, as adapted from [MKH12], can be formulated as:
\[\begin{split}\begin{array}{lllll} \displaystyle \textbf{Maximize} & \displaystyle D && & (1) \\ \displaystyle \textbf{Subject To} & \displaystyle \sum_{i \in I}{Y_i} = p && & (2) \\ & D \leq d_{ij} + M (2 - Y_{i} - Y_{j}) && \forall i \in I \quad \forall j > i & (3) \\ & Y_i \in \{0, 1\} && \forall i \in I & (4) \\ & && & \\ \displaystyle \textbf{Where} && i, j & = & \textrm{index of potential facility sites in set } I \\ && p & = & \textrm{the number of facilities to be sited} \\ && d_{ij} & = & \textrm{shortest distance or travel time between locations } i \textrm{ and } j \\ && D & = & \textrm{minimum distance between any two sited facilities } i \textrm{ and } j \\ && M & = & \textrm{some large number; such that } M \geq \max_{ij}\{d_{ij}\} \\ && Y_i & = & \begin{cases} 1, \textrm{if a facility is sited at location } i \\ 0, \textrm{otherwise} \\ \end{cases} \\ \end{array}\end{split}\]- Parameters:
- name
str
The problem name.
- problem
pulp.LpProblem
A
pulp
instance of an optimization model that contains constraints, variables, and an objective function.
- name
- Attributes:
- name
str
The problem name.
- problem
pulp.LpProblem
A
pulp
instance of an optimization model that contains constraints, variables, and an objective function.
- name
- __init__(name: str, problem: LpProblem, p_facilities: int)[source]¶
Initialize.
- Parameters:
- name
str
The desired name for the model.
- name
Methods
__init__
(name, problem, p_facilities)Initialize.
check_status
()Ensure a model is solved.
from_cost_matrix
(cost_matrix, p_facilities)Create a
PDispersion
object based on a cost matrix.from_geodataframe
(gdf_fac, facility_col, ...)Create a
PDispersion
object based on a geodataframe.solve
(solver)Solve the
PDispersion
model.- classmethod from_cost_matrix(cost_matrix: array, p_facilities: int, predefined_facilities_arr: array = None, name: str = 'p-dispersion')[source]¶
Create a
PDispersion
object based on a cost matrix.- Parameters:
- cost_matrix
np.array
A cost matrix in the form of a 2D array between origins and destinations.
- p_facilities
int
The number of facilities to be located.
- predefined_facilities_arr
numpy.array
(defaultNone
) A binary 1D array of service facilities that must appear in the solution. For example, consider 3 facilites
['A', 'B', 'C']
. If facility'B'
must be in the model solution, then the passed in array should be[0, 1, 0]
.- name
str
(default ‘p-dispersion’) The name of the problem.
- cost_matrix
- Returns:
Examples
>>> from spopt.locate.p_dispersion import PDispersion >>> from spopt.locate.util import simulated_geo_points >>> import geopandas >>> import pulp >>> import spaghetti
Create a regular lattice.
>>> lattice = spaghetti.regular_lattice((0, 0, 10, 10), 9, exterior=True) >>> ntw = spaghetti.Network(in_data=lattice) >>> streets = spaghetti.element_as_gdf(ntw, arcs=True) >>> streets_buffered = geopandas.GeoDataFrame( ... geopandas.GeoSeries(streets["geometry"].buffer(0.2).unary_union), ... crs=streets.crs, ... columns=["geometry"] ... )
Simulate points about the lattice.
>>> facility_points = simulated_geo_points(streets_buffered, needed=5, seed=6)
Snap the points to the network of lattice edges.
>>> ntw.snapobservations(facility_points, "facilities", attribute=True) >>> facilities_snapped = spaghetti.element_as_gdf( ... ntw, pp_name="facilities", snapped=True ... )
Calculate the cost matrix from origins to destinations. Origins and destinations are both
'facilities'
in this case.>>> cost_matrix = ntw.allneighbordistances( ... sourcepattern=ntw.pointpatterns["facilities"], ... destpattern=ntw.pointpatterns["facilities"] ... )
Create and solve a
PDispersion
instance from the cost matrix.>>> pdispersion_from_cost_matrix = PDispersion.from_cost_matrix( ... cost_matrix, p_fac=2 ... ) >>> pdispersion_from_cost_matrix = pdispersion_from_cost_matrix.solve( ... pulp.PULP_CBC_CMD(msg=False) ... )
Examine the solution.
>>> for dv in pdispersion_from_cost_matrix.fac_vars: ... if dv.varValue: ... print(f"facility {dv.name} is selected") facility y_0_ is selected facility y_1_ is selected
- classmethod from_geodataframe(gdf_fac: GeoDataFrame, facility_col: str, p_facilities: int, predefined_facility_col: str = None, distance_metric: str = 'euclidean', name: str = 'p-dispersion')[source]¶
Create a
PDispersion
object based on a geodataframe. Calculate the cost matrix between facilities, and then use the from_cost_matrix method.- Parameters:
- gdf_fac
geopandas.GeoDataFrame
Facility locations.
- facility_col
str
Facility candidate sites geometry column name.
- p_facilities
int
The number of facilities to be located.
- predefined_facility_col
str
(defaultNone
) Column name representing facilities are already defined. This a binary assignment per facility. For example, consider 3 facilites
['A', 'B', 'C']
. If facility'B'
must be in the model solution, then the column should be[0, 1, 0]
.- distance_metric
str
(default ‘euclidean’) A metric used for the distance calculations supported by scipy.spatial.distance.cdist.
- name
str
(default ‘p-dispersion’) The name of the problem.
- gdf_fac
- Returns:
Examples
>>> from spopt.locate.p_dispersion import PDispersion >>> from spopt.locate.util import simulated_geo_points >>> import geopandas >>> import pulp >>> import spaghetti
Create a regular lattice.
>>> lattice = spaghetti.regular_lattice((0, 0, 10, 10), 9, exterior=True) >>> ntw = spaghetti.Network(in_data=lattice) >>> streets = spaghetti.element_as_gdf(ntw, arcs=True) >>> streets_buffered = geopandas.GeoDataFrame( ... geopandas.GeoSeries(streets["geometry"].buffer(0.2).unary_union), ... crs=streets.crs, ... columns=["geometry"] ... )
Simulate points about the lattice.
>>> facility_points = simulated_geo_points(streets_buffered, needed=5, seed=6)
Snap the points to the network of lattice edges and extract as a
GeoDataFrame
object.>>> ntw.snapobservations(facility_points, "facilities", attribute=True) >>> facilities_snapped = spaghetti.element_as_gdf( ... ntw, pp_name="facilities", snapped=True ... )
Create and solve a
PDispersion
instance from theGeoDataFrame
object.>>> pdispersion_from_geodataframe = PDispersion.from_geodataframe( ... facilities_snapped, ... "geometry", ... p_fac=2, ... distance_metric="euclidean" ... ) >>> pdispersion_from_geodataframe = pdispersion_from_geodataframe.solve( ... pulp.PULP_CBC_CMD(msg=False) ... )
Examine the solution.
>>> for dv in pdispersion_from_geodataframe.fac_vars: ... if dv.varValue: ... print(f"facility {dv.name} is selected") facility y_0_ is selected facility y_1_ is selected