# Set of Vehicles in radius and selection of minimal disutility (min_disutility_in_radius) specification
In matching(self, user_buffer: List[User]):
```
# Note user_buffer = list of users that have sent a request, ordered in the order of request receipt
for each user in user_buffer:
default_filter = WaitingInRadius(radius)
default_priority = Priority([default_filter])
vehicles = default_priority.get_vehicles_pool(user.position)
vehicle_candidates = []
for vehicle in vehicles:
a_priori_feasibility = pre_compute_feasibility(vehicle, user)
if a_priori_feasibility:
# Compute the best plan including user pick up
user_pickup = cast user into pickup activity
potential_plan = replanning(vehicle, [user_pickup, user_dropoff])
# Note that disutility is a float, inf if potential_plan is unfeasible
disutility = compute_disutility(vehicle, potential_plan)
if disutility is not inf:
Append (vehicle, disutility) in vehcile_candidates list
if vehicle_candidates is not empty:
Select the vehicle candidate with the min disutility in the list to be matched with request j
Match
# Be carefull here - test right now if passenger is going to accept the waiting time before pick-up
```
Methods and functions to be defined:
```
replanning(self,
veh: Vehicle,
new_activities: Optional[Set[VehicleActivity]] = None,
) -> Queue[VehicleActivity]
'''NB: When used in min_disutility_in_radius startegy:
- current activityPlan of vehicle only contains dropoff activities
- new_activities corresponds to a set with the pickup and the dropoff if one user
The default behavior of this function is the following:
- insert pickup activity at the first index of vehicle's current plan
- push dropoff activity at the very end of vehicle's current plan
'''
```
```
pre_compute_feasibility(vehicle, user) -> Bool:
'''By default this function return True if vehicle is available, False otherwise.
A vehicle is said to be unavailable if: (i) it is full (ii) first activity in vehicle's plan is a pickup .
'''
```
```
compute_disutility(Vehicle: veh, new_plan: Queue[VehicleActivity]) -> float
# Main objective of the mobility service is to minimize travelers disutility
disutility = quality_disutility(veh, new_plan)
return disutility
```
## Quality-based
Money is taken as base reference for disutility evaluation.
Note: temporal cost in not necessary since we use trip-based MFD with relatively stable speeds, distance cost is sufficient.
```
quality_disutility(vehicle: Vehicle, new_plan: Queue[VehicleActivity]) -> float:
total_disutility = 0
if include_potential_user_in_disutility:
users = all users appering in new_plan
else:
users = users appearing in new_plan without the user that has been added in new_plan compared to vehicle's current plan
for user in users:
disutility = get_disutility(user, vehicle.current_plan, new_plan)
total_disutility += disutility
return total_disutility
```
```
get_disutility(user: User, vehicle: Vehicle, new_plan: Queue[VehicleActivity]) -> float:
marginal_cost, detour_ratio = get_cost(user, vehicle, new_plan)
if detour_ratio > user.max_detour_ratio:
return +inf
return marginal_cost
```
```
get_cost(user: User, vehicle: Vehicle, new_plan: Queue[VehicleActivity]) -> float
current_plan_truncated = truncate_plan(user, vehicle.current_plan)
current_remaining_distance = get_remaining_distance(vehicle, current_plan_truncated)
new_plan_truncated = truncate_plan(user, new_plan)
new_remaining_distance = get_remaining_distance(vehicle, new_plan)
marginal_cost = user.distance_value * (new_remaining_distance - current_remaining_distance) - get_discount()
# Check user.traveled_distance is valid
total_distance = user.traveled_distance + new_remaining_distance
detour_ratio = total_distance / user.shortest_path_distance
return marginal_cost, detour_ratio
```
```
truncate_plan(user: User, vehicleplan: Queue[VehicleActivity])
''' Methods that truncates plan after user's drop-off.'''
```
```
get_remaining_distance(vehicle: Vehicle, plan: ActivityPlan) -> float:
'''This function returns the remaining distance for vehicle to achieve plan.
'''
```
```
get_discount() -> Float:
'''This function is basic by default, the discount is fixed by a parameter of the mobility service. It may be overwritten by user so as to take into account more detailed discount schemes.
'''
return discount
```
Ex: truncate_plan(user_1, [O_2, D_1, D_2]) -> [O_2, D_1]

[Link to full example.](https://hackmd.io/mqUVHG0TS4KQciNsv4U5Aw)
## Profit-based (optional, to be implemented in next versions !)
Main objective of the mobility service is to earn the max profit.
```
compute_profit(Vehicle, Queue[VehicleActivity]) -> float
revenue = compute_revenue(Vehicle, Queue[VehicleActivity])
costs = compute_cost(Vehicle, Queue[VehicleActivity]) # mostly distance base
profit = revenue - costs
return profit
```
```
profit_disutility(new_plan):
profit_new_plan = compute_profit(veh, new_plan)
profit_current_plan = compute_profit(veh, veh.current_plan)
disutility = - (profit_new_plan - profit_current_plan)
return disutility
```
* Note: utility = difference between two costs