# Nearest available vehicle with priority
## Filters
### Generic filters
```python=
from abc import ABC, abstractmethod
class VehicleFilter(ABC):
def __init__(self, layer: AbstractLayer):
self.layer = layer
@abstractmethod
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
pass
def __and__(self, other):
return CombinedVehicleFilter([self, other])
def __not__(self):
pass
class CombinedVehicleFilter(object):
def __init__(self, filters: List[VehicleFilter]):
self.filters = filters
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
call each filters get_vehicles_pool method and combine them using and operator
"""
def __and__(self, other):
if isinstance(other, CombinedFilter):
return CombinedFilter(self.filters+other.filters)
elif isinstance(other, VehicleFilter):
return CombinedFilter(self.filters+[other])
class InRadiusFilter(VehicleFilter):
def __init__(self, layer: AbstractLayer, radius: float):
super().__init__(layer)
serf.radius = radius
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array), if vehicle in self.radius True else False
"""
class IsNearestFilter(VehicleFilter):
def __init__(self, layer: AbstractLayer, multiple: bool):
super().__init__(layer)
self.multiple = multiple
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array), if vehicle is nearest vehicle from position True else False
"""
class IsWaiting(VehicleFilter):
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array), if vehicle.waiting True else False
"""
### Zoning-based filter
class InZoneFilter(VehicleFilter):
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array), if vehicle and position in same zone True else False
"""
# TODO - garde-fou -> throw / catch error when the simulation does not include zoning.
# Then just return True for all (as if single zone) or a radius-based filter?
```
### Deposit-based filters
```python=
class InZonalDepot(VehicleFilter):
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array), if vehicle is in a depot that is the zone of position True, else False
If self.multiple is False, only return True for the first vehicle that entered the depot, else True for
"""
class InNearestDepot(VehicleFilter):
def __init__(self, layer: AbstractLayer, multiple: bool):
super().__init__(layer)
self.multiple = multiple
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array).
If self.multiple: if vehicle is in the nearest depot from position True, else False
If not self.multiple: if vehicle is the vehicle of the nearest depot waiting for the longest time True, else False
"""
class InNearestZonalDepot(VehicleFilter):
def __init__(self, layer: AbstractLayer, multiple: bool):
super().__init__(layer)
self.multiple = multiple
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array).
If self.multiple: if vehicle is in the nearest zonal depot (depot and user are in the same zone) from position True, else False
If not self.multiple: if vehicle is the vehicle from the nearest zonal depot waiting for the longest time True, else False.
"""
class ToNearestDepot(VehicleFilter):
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array), if vehicle is heading to the nearest depot from position True, else False
"""
class ToZonalDepot(VehicleFilter):
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array), if vehicle is heading to a depot that is the zone of position True, else False
"""
class ToNearestZonalDepot(VehicleFilter):
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Return a mask (boolean array), if vehicle is heading to the nearest zonal depot (depot and user are in the same zone) from position True, else False
"""
```
## Class `CombinedFilters`
```python=
# Example:
inzone_inradius_filter: CombinedFilter = InRadiusFilter(layer, 1000) & InZoneFilter(layer)
mask: List[bool] = inzone_inradius_filter([0, 0], vehicles)
```
```python=
waiting_inzone_filter: CombinedFilter = IsWaiting(layer) & InZoneFilter(layer)
waiting_innearestdepot_filter: CombinedFilter = IsWaiting(layer) & InNearestDepot(layer)
waiting_innearestzonaldepot_filter: CombinedFilter = IsWaiting(layer) & InNearestZonalDepo(layer)
waiting_inzonaldepot_filter: CombinedFilter = IsWaiting(layer) & InZonalDepot(layer)
#...
tozonaldepot_inzone_filter: CombinedFilter = InZoneFilter(layer) & ToZonalDepot(layer)
```
## Class ```Priority```
```python=
class Priority(object):
def __init__(self, filters: List[CombinedVehicleFilter / VehicleFilter]):
self.filters = filters
def get_mask(self,
vehicles: List[Vehicle],
position: List[float] = None,
deposits: List[Depot] = None) -> List[bool]:
"""
Call each filter and break when a mask contains at least a True
"""
default_priority = Priority([InRadiusFilter(layer, 1000)])
waiting_innearestzonaldepot_filter: CombinedFilter = IsWaiting(layer) & InNearestZonalDepo(layer)
#waiting_inzonaldepot_filter: CombinedFilter = IsWaiting(layer) & InZonalDepot(layer)
tonearestzonaldepot_filter: CombinedFilter = ToNearestZonalDepot(layer)
waiting_inzone_filter: CombinedFilter = IsWaiting(layer) & InZoneFilter(layer)
waiting_filter: CombinedFilter = IsWaiting(layer)
default_priority = Priority([waiting_innearestzonaldepot_filter,
tonearestzonaldepot_filter,
waiting_inzone_filter,
waiting_filter])
ls_filters = [InRadiusFilter(layer, radius) for radius in range(min_radius, max_radius, step_radius)]
iterative_priority = Priority(ls_filters)
```
## Class ```Strategy```
### For Ride-hailing
```python=
class PriorityStrategy1(Strategy):
def __init__(self, layer, priority: Priority = Priority([])):
# default priority must be as defined in l. 209
super().__init__()
self.layer: layer
self.priority: priority
def matching(self,
user_buffer: List[User],
vehicles: List[Vehicle],
deposits: List[Depot] = None):
unmatched_vehicles = vehicles
for user in user_buffer:
mask = self.priority.get_mask(unmatched_vehicles, user.position, deposits)
if any(mask):
# Get vehicle_pool based on priority
vehicle_pool = unmatched_vehicles[mask]
# Return closes vehicle from pool
vehicle = unmatched_vehicles[
IsNearestFilter(layer, multiple = False).get_mask(unmatched_vehicles, user.position)]
# TODO - Match vehicle with user
# TODO - REMOVE VEHICLE FROM unmatched_vehicles FOR IT NOT TO BE MATCHED TWICE
else:
# Tried all priority without success
# User cannot be matched.
return matching
```
### For Ride-Sharing:
To be defined.