Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add examples section to locate module #198

Merged
merged 2 commits into from
Sep 26, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,15 @@ Model based approaches for aggregating a large set of geographic units (with sma
region.Spenc
region.WardSpatial

Locate Methods
--------------

.. autosummary::
:toctree: generated/

locate.coverage.LSCP
locate.coverage.MCLP
locate.PCenter
locate.PMedian


19 changes: 17 additions & 2 deletions spopt/locate/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ class BaseOutputMixin:

def client_facility_array(self) -> None:
"""
Create an array 2d $m$ x $n$, where m is number of clients and n is number of facilities.
Create an array 2d MxN, where m is number of clients and n is number of facilities.
"""
if hasattr(self, "fac2cli"):
self.cli2fac = [[] for i in range(self.aij.shape[0])]
Expand All @@ -63,7 +63,7 @@ def uncovered_clients(self) -> None:

class CoveragePercentageMixin:
"""
Mixin for calculate the percentage of area covered
Mixin to calculate the percentage of area covered
"""

def get_percentage(self):
Expand All @@ -74,7 +74,22 @@ def get_percentage(self):


class MeanDistanceMixin:
"""
Mixin to calculate the mean distance between demand and facility sites chosen
"""

def get_mean_distance(self, weight: np.array):
"""
Calculate the mean distance
Parameters
----------
weight: np.array
weight of all demand points

Returns
-------
None
"""
self.mean_dist = self.problem.objective.value() / weight.sum()


Expand Down
195 changes: 193 additions & 2 deletions spopt/locate/coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,51 @@ def from_cost_matrix(
Returns
-------
LSCP object

Examples
--------
>>> from spopt.locate.coverage import LSCP
>>> from spopt.locate.util import simulated_geo_points
>>> import pulp
>>> import spaghetti
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we are going to have spaghetti in the doc string examples, then we should probably also have in requirements.txt.


Create regular lattice

>>> lattice = spaghetti.regular_lattice((0, 0, 10, 10), 9, exterior=True)
>>> ntw = spaghetti.Network(in_data=lattice)
>>> street = spaghetti.element_as_gdf(ntw, arcs=True)
>>> street_buffered = geopandas.GeoDataFrame(
... geopandas.GeoSeries(street["geometry"].buffer(0.2).unary_union),
... crs=street.crs,
... columns=["geometry"])

Simulate points belong to lattice

>>> demand_points = simulated_geo_points(street_buffered, needed=100, seed=5)
>>> facility_points = simulated_geo_points(street_buffered, needed=5, seed=6)

Snap points to the network

>>> ntw.snapobservations(demand_points, "clients", attribute=True)
>>> clients_snapped = spaghetti.element_as_gdf(ntw, pp_name="clients", snapped=True)
>>> ntw.snapobservations(facility_points, "facilities", attribute=True)
>>> facilities_snapped = spaghetti.element_as_gdf(ntw, pp_name="facilities", snapped=True)

Calculate the cost matrix
>>> cost_matrix = ntw.allneighbordistances(
... sourcepattern=ntw.pointpatterns["clients"],
... destpattern=ntw.pointpatterns["facilities"])

Create LSCP instance from cost matrix

>>> lscp_from_cost_matrix = LSCP.from_cost_matrix(cost_matrix, max_coverage=8)
>>> lscp_from_cost_matrix = lscp_from_cost_matrix.solve(pulp.PULP_CBC_CMD(msg=False))

Get facility lookup demand coverage array

>>> lscp_from_cost_matrix.facility_client_array()
>>> lscp_from_cost_matrix.fac2cli

"""

r_fac = range(cost_matrix.shape[1])
Expand Down Expand Up @@ -116,6 +161,48 @@ def from_geodataframe(
Returns
-------
LSCP object

Examples
--------
>>> from spopt.locate.coverage import LSCP
>>> from spopt.locate.util import simulated_geo_points
>>> import pulp
>>> import spaghetti

Create regular lattice

>>> lattice = spaghetti.regular_lattice((0, 0, 10, 10), 9, exterior=True)
>>> ntw = spaghetti.Network(in_data=lattice)
>>> street = spaghetti.element_as_gdf(ntw, arcs=True)
>>> street_buffered = geopandas.GeoDataFrame(
... geopandas.GeoSeries(street["geometry"].buffer(0.2).unary_union),
... crs=street.crs,
... columns=["geometry"])

Simulate points belong to lattice

>>> demand_points = simulated_geo_points(street_buffered, needed=100, seed=5)
>>> facility_points = simulated_geo_points(street_buffered, needed=5, seed=6)

Snap points to the network

>>> ntw.snapobservations(demand_points, "clients", attribute=True)
>>> clients_snapped = spaghetti.element_as_gdf(ntw, pp_name="clients", snapped=True)
>>> ntw.snapobservations(facility_points, "facilities", attribute=True)
>>> facilities_snapped = spaghetti.element_as_gdf(ntw, pp_name="facilities", snapped=True)

Create LSCP instance from cost matrix

>>> lscp_from_geodataframe = LSCP.from_geodataframe(clients_snapped, facilities_snapped,
... "geometry", "geometry",
... max_coverage=8, distance_metric="euclidean")
>>> lscp_from_geodataframe = lscp_from_geodataframe.solve(pulp.PULP_CBC_CMD(msg=False))

Get facility lookup demand coverage array

>>> lscp_from_geodataframe.facility_client_array()
>>> lscp_from_geodataframe.fac2cli

"""

dem = gdf_demand[demand_col]
Expand Down Expand Up @@ -152,7 +239,7 @@ def from_geodataframe(

def facility_client_array(self) -> None:
"""
Create an array 2d $m$ x $n$, where m is number of facilities and n is number of clients. Each row represent a facility and has an array containing clients index meaning that the $facility_0$ cover the entire array.
Create an array 2d MxN, where m is number of facilities and n is number of clients. Each row represent a facility and has an array containing clients index meaning that the facility-i cover the entire array.

Returns
-------
Expand Down Expand Up @@ -250,6 +337,56 @@ def from_cost_matrix(
Returns
-------
MCLP object

Examples
--------

>>> from spopt.locate.coverage import MCLP
>>> from spopt.locate.util import simulated_geo_points
>>> import pulp
>>> import spaghetti

Create regular lattice

>>> lattice = spaghetti.regular_lattice((0, 0, 10, 10), 9, exterior=True)
>>> ntw = spaghetti.Network(in_data=lattice)
>>> street = spaghetti.element_as_gdf(ntw, arcs=True)
>>> street_buffered = geopandas.GeoDataFrame(
... geopandas.GeoSeries(street["geometry"].buffer(0.2).unary_union),
... crs=street.crs,
... columns=["geometry"])

Simulate points belong to lattice

>>> demand_points = simulated_geo_points(street_buffered, needed=100, seed=5)
>>> facility_points = simulated_geo_points(street_buffered, needed=5, seed=6)

Snap points to the network

>>> ntw.snapobservations(demand_points, "clients", attribute=True)
>>> clients_snapped = spaghetti.element_as_gdf(ntw, pp_name="clients", snapped=True)
>>> ntw.snapobservations(facility_points, "facilities", attribute=True)
>>> facilities_snapped = spaghetti.element_as_gdf(ntw, pp_name="facilities", snapped=True)

Calculate the cost matrix

>>> cost_matrix = ntw.allneighbordistances(
... sourcepattern=ntw.pointpatterns["clients"],
... destpattern=ntw.pointpatterns["facilities"])

Simulate demand weights from 1 to 12

>>> ai = numpy.random.randint(1, 12, 100)

Create MCLP instance from cost matrix

>>> mclp_from_cost_matrix = MCLP.from_cost_matrix(cost_matrix, ai, max_coverage=7, p_facilities=4)
>>> mclp_from_cost_matrix = mclp_from_cost_matrix.solve(pulp.PULP_CBC_CMD(msg=False))

Get facility lookup demand coverage array

>>> mclp_from_cost_matrix.facility_client_array()
>>> mclp_from_cost_matrix.fac2cli
"""
r_fac = range(cost_matrix.shape[1])
r_cli = range(cost_matrix.shape[0])
Expand Down Expand Up @@ -313,6 +450,60 @@ def from_geodataframe(
Returns
-------
MCLP object

Examples
--------
>>> from spopt.locate.coverage import MCLP
>>> from spopt.locate.util import simulated_geo_points
>>> import pulp
>>> import spaghetti

Create regular lattice

>>> lattice = spaghetti.regular_lattice((0, 0, 10, 10), 9, exterior=True)
>>> ntw = spaghetti.Network(in_data=lattice)
>>> street = spaghetti.element_as_gdf(ntw, arcs=True)
>>> street_buffered = geopandas.GeoDataFrame(
... geopandas.GeoSeries(street["geometry"].buffer(0.2).unary_union),
... crs=street.crs,
... columns=["geometry"])

Simulate points belong to lattice

>>> demand_points = simulated_geo_points(street_buffered, needed=100, seed=5)
>>> facility_points = simulated_geo_points(street_buffered, needed=5, seed=6)

Snap points to the network

>>> ntw.snapobservations(demand_points, "clients", attribute=True)
>>> clients_snapped = spaghetti.element_as_gdf(ntw, pp_name="clients", snapped=True)
>>> ntw.snapobservations(facility_points, "facilities", attribute=True)
>>> facilities_snapped = spaghetti.element_as_gdf(ntw, pp_name="facilities", snapped=True)

Simulate demand weights from 1 to 12

>>> ai = numpy.random.randint(1, 12, 100)
>>> clients_snapped['weights'] = ai

Create MCLP instance from geodataframe

>>> mclp_from_geodataframe = MCLP.from_geodataframe(
... clients_snapped,
... facilities_snapped,
... "geometry",
... "geometry",
... "weights",
... max_coverage=7,
... p_facilities=4,
... distance_metric="euclidean"
... )

>>> mclp_from_geodataframe = mclp_from_geodataframe.solve(pulp.PULP_CBC_CMD(msg=False))

Get facility lookup demand coverage array

>>> mclp_from_geodataframe.facility_client_array()
>>> mclp_from_geodataframe.fac2cli
"""
service_load = gdf_demand[weights_cols].to_numpy()
dem = gdf_demand[demand_col]
Expand Down Expand Up @@ -351,7 +542,7 @@ def from_geodataframe(

def facility_client_array(self) -> None:
"""
Create an array 2d $m$ x $n$, where m is number of facilities and n is number of clients. Each row represent a facility and has an array containing clients index meaning that the $facility_0$ cover the entire array.
Create an array 2d MxN, where m is number of facilities and n is number of clients. Each row represent a facility and has an array containing clients index meaning that the facility-i cover the entire array.

Returns
-------
Expand Down
Loading