Zone Relations¶
Zone relations define adjacency constraints between zones. They are represented as a symmetric matrix where each cell specifies how two zones are allowed (or forbidden) to neighbor each other.
Relations are optional. If not provided, GenPlanner uses a default matrix built from forbidden neighborhood rules.
Relation values¶
The matrix cells use the Relation enum:
NEUTRAL— no constraintNEIGHBOR— zones must / are encouraged to be neighborsFORBIDDEN— zones cannot be neighbors
Example:
from genplanner import Relation
print(Relation.FORBIDDEN.value) # "forbidden"
ZoneRelationMatrix¶
ZoneRelationMatrix is a symmetric adjacency matrix with O(1) access.
Key properties:
Matrix is always symmetric.
Default relation is
NEUTRAL.Zones must be unique and hashable.
Works with any
Zone, but typically used withTerritoryZone.
Build Empty matrix¶
from genplanner import ZoneRelationMatrix
from genplanner.zones import default_terr_zones
zones = [
default_terr_zones.residential_terr,
default_terr_zones.industrial_terr,
]
mat = ZoneRelationMatrix.empty(zones)
print(mat.is_forbidden(zones[0], zones[1])) # False
Build from explicit pairs¶
You can explicitly define neighbor or forbidden pairs:
from genplanner import ZoneRelationMatrix
from genplanner.zones import default_terr_zones
res = default_terr_zones.residential_terr
ind = default_terr_zones.industrial_terr
mat = ZoneRelationMatrix.from_pairs(
zones=[res, ind],
forbidden=[(res, ind)]
)
assert mat.is_forbidden(res, ind)
Build from_kind_forbidden (recommended)¶
GenPlanner ships with a predefined set:
from genplanner import FORBIDDEN_NEIGHBORHOOD
print(FORBIDDEN_NEIGHBORHOOD)
The set contains pairs of TerritoryZoneKind that must not neighbor.
How it works¶
from_kind_forbidden:
Groups zones by their
kind.For each forbidden kind pair
(A, B), marks all zones of kind A and all zones of kind B as mutually forbidden.Ensures symmetry.
Example¶
from genplanner import ZoneRelationMatrix, FORBIDDEN_NEIGHBORHOOD
from genplanner.zones import default_terr_zones
zones = [
default_terr_zones.residential_terr,
default_terr_zones.industrial_terr,
default_terr_zones.business_terr,
]
mat = ZoneRelationMatrix.from_kind_forbidden(
zones=zones,
kind_forbidden=FORBIDDEN_NEIGHBORHOOD,
)
# residential vs industrial is forbidden (by default rules)
assert mat.is_forbidden(
default_terr_zones.residential_terr,
default_terr_zones.industrial_terr
)
Build from DataFrame¶
You can construct a matrix from a square pandas DataFrame.
Requirements:
Example (Zone objects as labels)¶
import pandas as pd
from genplanner import ZoneRelationMatrix
from genplanner.zones import default_terr_zones
res = default_terr_zones.residential_terr
ind = default_terr_zones.industrial_terr
df = pd.DataFrame(
data=[
[0, -1],
[-1, 0],
],
index=[res, ind],
columns=[res, ind],
)
mat = ZoneRelationMatrix.from_dataframe(df)
assert mat.is_forbidden(res, ind)
Allow non-symmetric input¶
If you want to load a DataFrame that is not symmetric (e.g., partially filled), disable symmetry validation:
mat = ZoneRelationMatrix.from_dataframe(df, require_symmetric=False)
Matrix Subsets¶
You can restrict a matrix to a subset of zones:
sub = mat.subset([res])
print(sub.zones)
Pretty print¶
The matrix can be visualized:
print(mat.to_pretty_string())
Output example:
res ind bus
res · ✗ ·
ind ✗ · ·
bus · · ·
Using with GenPlanner¶
Pass a matrix to features2terr_zones:
from genplanner import GenPlanner
gp = GenPlanner(features_gdf=features)
zones, roads = gp.features2terr_zones(
funczone=basic_func_zone,
relation_matrix=mat,
)
API reference¶
Core classes¶
Symmetric matrix of relations between zones. |
|
Cell value in adjacency matrix. |
|
set() -> new empty set object set(iterable) -> new set object |