Competitive provision

This type of provision is used for service types such as school, kindergarten etc. Where each demand occupies some space and doesn’t let any other demand occupy it.

[1]:
import pandas as pd

blocks_gdf = pd.read_pickle('./../../data/saint_petersburg/blocks.pickle')
accessibility_matrix = pd.read_pickle('./../../data/saint_petersburg/accessibility_matrix_intermodal.pickle')

Provision assessment

[3]:
from blocksnet.config import service_types_config

service_type = 'school'
_, demand, accessibility = service_types_config[service_type].values()
demand, accessibility
[3]:
(120, 15)

In most cases max_depth=1 is optimal, but for this example max_depth=3 will be used

[14]:
from blocksnet.analysis.provision import competitive_provision

gdf = blocks_gdf.rename(columns={f'capacity_{service_type}':'capacity'})
blocks_df, links_df = competitive_provision(gdf, accessibility_matrix, accessibility, demand, max_depth=3)
2025-09-19 18:36:22.555 | INFO     | blocksnet.analysis.provision.competivive.core:_initialize_provision_df:29 - Initializing provision DataFrame
2025-09-19 18:36:22.559 | WARNING  | blocksnet.analysis.provision.competivive.core:_initialize_provision_df:33 - No demand in columns. Imputing using population column and demand parameter
2025-09-19 18:36:22.586 | INFO     | blocksnet.analysis.provision.competivive.core:_supply_self:56 - Supplying blocks with own capacities
2025-09-19 18:36:22.700 | INFO     | blocksnet.analysis.provision.competivive.core:competitive_provision:175 - Setting and solving LP problems until max depth or break condition reached
100%|██████████| 3/3 [00:17<00:00,  5.80s/it]
2025-09-19 18:36:40.117 | SUCCESS  | blocksnet.analysis.provision.competivive.core:competitive_provision:188 - Provision assessment finished
[15]:
blocks_df.head()
[15]:
demand capacity demand_left demand_within demand_without capacity_left capacity_within capacity_without provision_strong provision_weak
0 0 0 0 0 0 0 0 0 NaN NaN
1 0 0 0 0 0 0 0 0 NaN NaN
2 13 0 13 0 0 0 0 0 0.0 0.0
3 9 0 9 0 0 0 0 0 0.0 0.0
4 52 942 0 52 0 0 734 156 1.0 1.0
[16]:
links_df.head()
[16]:
value
source target
10 710 12.0
15 8838 1.0
35 115 35.0
39 4544 43.0
41 262 86.0

Additional features

[18]:
from blocksnet.analysis.provision import provision_strong_total, provision_weak_total

p_strong = provision_strong_total(blocks_df)
p_weak = provision_weak_total(blocks_df)

float(p_strong), float(p_weak)
[18]:
(0.6890279622706392, 0.7433122288715732)

Visualization

[21]:
ax=blocks_gdf.plot(color='#ddd', figsize=(10,8))
blocks_gdf[['geometry']].join(blocks_df).plot(ax=ax, column='provision_strong', cmap='RdYlGn', vmin=0, vmax=1, legend=True)
ax.set_title(f'Pstrong = {round(p_strong, 2)}, Pweak = {round(p_weak, 2)}')
ax.set_axis_off()
../../../_images/examples_analysis_provision_competitive_11_0.png