---
# System prepended metadata

title: Nearest available vehicle with priority

---

# 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.

