-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathutils.py
More file actions
238 lines (202 loc) · 10.1 KB
/
utils.py
File metadata and controls
238 lines (202 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# importing nessary libraries
import copy
import random
import numpy as np
import matplotlib.pyplot as plt
from itertools import permutations
import math
from math import radians, sin, cos, sqrt, atan2
import matplotlib.pyplot as plt
from matplotlib.patches import Ellipse
# Constants
OTD = 60 # Order Time Delivery limit in minutes
first_mile_speed = 25 # Speed to reach pickup location in km/h
last_mile_speed = 15 # Speed from pickup to delivery location in km/h
return_mile_speed = 40 # Speed to return from delivery location to origin in km/h
batch_size = 100 # Number of orders that can be assigned to a rider at once
first_mile_cost = 2 # Cost to reach pickup location in $/km
last_mile_cost = 5 # Cost to deliver from pickup location to delivery location in $/km
return_mile_cost = 1.5 # Cost to return from delivery location to origin in $/km
ellipse_a = 0.5 # Ellipse axes lengths a
ellipse_b = 0.5 # Ellipse axes lengths b
roundoff_digit = 4 # Round off digit for floating point numbers
avg_speed = 25 # average speed of the rider needs to be removed
our_cut = 0.08 # variable from 8% to 15%
avg_cost_per_km = 2.5 # needs to be remove
rider_capacity = 20 # maybe variable rider to rider
min_profit = 0 # minimum profit to assign an order to a rider needs to be 0
# if there are multiple order assigned so then maximum percentage of bearable loss of total profit
maximum_percentage_of_bearable_loss_when_mulitple_orders_assign = 0.5 # 50% loss is bearable if mulitple orders are assigned to a rider at once
#here the all utility functions are defined
from Optimize_route import optimize_route
def calculate_distance(coordinate1, coordinate2, roundoff_digit=2):
"""
Calculate the Euclidean distance between two coordinates.
"""
print("Calculating distance")
print(f"coordinate1 = {coordinate1}")
print(f"coordinate2 = {coordinate2}")
coord1 = coordinate1[0]
coord2 = coordinate2[0]
print(f"coord1 = {coord1}")
print(f"coord2 = {coord2}")
dist = np.sqrt((coord1[0] - coord2[0]) ** 2 + (coord1[1] - coord2[1]) ** 2)
dist = round(dist, roundoff_digit)
return dist
def calculate_distance_for_delhivery_time(x,y):
print("Calculating distance for delhivery time")
distance = 0
distance = distance + np.sqrt((x[0] - y[0]) ** 2 + (x[1] - y[1]) ** 2)
return distance
def print_rider_details(riders):
"""
Print details of all riders.
"""
print(".........................../")
for rider in riders:
if len(rider["CART"]) == 0:
print(f"{rider['RIDER_ID']} No orders in the cart.")
continue
print(f'RIDER_ID = {rider["RIDER_ID"]}, Our Profit = {rider["our_profit"]}, Total Order Value = {rider["Total_order_value"]}, Total Distance = {rider["total_distance"]}, Total Orders = {len(rider["CART"])} ')
for i in range(len(rider["CART"])):
order = rider["CART"][i]
times = rider["delivery_times"]
time = times[i]
key = list(time.keys())[0]
print(f"Delhiver Time of Order id {key} is {time[key]}")
print(f"first_mile_distance = {order['first_mile_distance']} and last_mile_distance = {order['last_mile_distance']} and first_mile_time = {order['first_mile_time']} and last_mile_time = {order['last_mile_time']}")
print(".........................../")
def append_order(order_orig, rider_orig):
# try:
order=copy.deepcopy(order_orig)
rider=copy.deepcopy(rider_orig)
if len(rider["CART"])==0:
rider["CART"].append(order)
print(f"Order {order['ORDER_ID']} appended to rider {rider['RIDER_ID']}")
print("appending if case")
rider["route"] = [order["pickup_coordinates"],order["delivery_coordinates"]]
rider["rider_order_status"].append("PICKUP")
rider["coordinates"] = [[order["pickup_coordinates"],order["delivery_coordinates"]]]
rider["rider_capacity"] -= order.get("order_volume", 0)
order["Rider"] = rider["RIDER_ID"]
rider["Total_order_value"] += order["Order_value"]
rider["our_profit"] = round((rider["Total_order_value"] * our_cut),roundoff_digit) - rider["total_distance"] * avg_cost_per_km
rider["total_distance"] = calculate_distance([rider["current_coordinates"]], [order["pickup_coordinates"]])+calculate_distance([order["pickup_coordinates"]], [order["delivery_coordinates"]])
delhivery_time = calculate_delivery_time(rider)
print("delhivery timemmmm",delhivery_time)
rider["delivery_times"] = calculate_delivery_time(rider)
order["first_mile_distance"] = calculate_distance([rider["current_coordinates"]], [order["pickup_coordinates"]])
order["last_mile_distance"] = calculate_distance([order["pickup_coordinates"]], [order["delivery_coordinates"]])
order["first_mile_time"] = (order["first_mile_distance"]/first_mile_speed)*60
order["last_mile_time"] = (order["last_mile_distance"]/last_mile_speed)*60
return rider
else:
print("appending else case")
rider["CART"].append(order)
rider["coordinates"].append([order["pickup_coordinates"],order["delivery_coordinates"]])
best_route_coordinates, min_distance, best_flags = optimize_route(rider)
rider["route"] = best_route_coordinates # Assign the best route to rider["route"]
rider["rider_flags"] = best_flags
rider["rider_order_status"].append("DELIVERY")
order["Rider"] = rider["RIDER_ID"]
print(f"Order {order['ORDER_ID']} appended to rider {rider['RIDER_ID']}")
rider["rider_capacity"] -= order["order_volume"]
rider["total_distance"] = min_distance
rider["Total_order_value"] += order["Order_value"]
print([rider])
delhivery_time = calculate_delivery_time(rider)
rider["delivery_times"] = delhivery_time
rider["our_profit"] = total_profit(rider)
print_rider_details([rider])
order["first_mile_distance"] = calculate_distance([rider["current_coordinates"]], [order["pickup_coordinates"]])
order["last_mile_distance"] = calculate_distance([order["pickup_coordinates"]], [order["delivery_coordinates"]])
order["first_mile_time"] = (order["first_mile_distance"]/first_mile_speed)*60
order["last_mile_time"] = (order["last_mile_distance"]/last_mile_speed)*60
return rider
def calculate_delivery_time(rider):
print("Calculating delivery time")
print("rider cart ",rider["CART"])
delhivery_times = []
delhivery_time = 0
if len(rider["CART"]) == 0:
print("No orders in the cart. and At that time this function need not to call something wrong")
return delhivery_times
if len(rider["CART"]) == 1:
order = rider["CART"][0]
pickup = order["pickup_coordinates"]
delhivery = order["delivery_coordinates"]
delhivery_time = (calculate_distance_for_delhivery_time(rider["current_coordinates"], pickup)/first_mile_speed)*60
delhivery_time = delhivery_time + (calculate_distance_for_delhivery_time(pickup, delhivery)/last_mile_speed)*60
delhivery_times.append({order["ORDER_ID"]:delhivery_time})
return delhivery_times
else:
current_coordinates = rider["current_coordinates"]
print("current coordinates",current_coordinates)
orders = rider["CART"]
print(f"Rider CART have :{len(orders)}")
coordinats = rider["route"]
for order in orders:
pickup = order["pickup_coordinates"]
delhivery = order["delivery_coordinates"]
print(f"Coordinates:{coordinats}")
print("current coordinates",current_coordinates)
print(f"Pickup:{pickup}")
print(f"Delhivery:{delhivery}")
i = coordinats.index(pickup)
j = coordinats.index(delhivery)
print("i = ",i)
print("j = ",j)
# delhivery_time = delhivery_time + (calculate_distance_for_delhivery_time(current_coordinates, coordinats[i])/first_mile_speed)*60
delhivery_time = delhivery_time + (calculate_distance_for_delhivery_time(coordinats[j-1], coordinats[j])/last_mile_speed)*60
delhivery_times.append({order["ORDER_ID"]:delhivery_time})
return delhivery_times
def update_rider(rider):
return rider
def get_min_OTD(orders):
"""
Get the minimum OTD from a list of orders.
"""
OTD = math.inf
try:
for order in orders:
if order["OTD"] < OTD:
OTD = order["OTD"]
return OTD
except Exception as e:
print(f"Error getting min OTD: {e}")
return 0
def total_profit(rider):
tot_profit = 0
"""
Calculate the total profit if rider pick this order .
"""
try:
if len(rider["CART"]) == 0:
print("Total profit function called and cart is empty.")
return tot_profit
if len(rider["CART"]) == 1:
revenue = rider["Total_order_value"]*our_cut
order = rider["CART"][0]
cost = calculate_distance([rider["current_coordinates"]], [order["pickup_coordinates"]]) * first_mile_cost
cost = cost + calculate_distance([order["pickup_coordinates"]], [order["delivery_coordinates"]]) * last_mile_cost
tot_profit = revenue - cost
return tot_profit
else:
cost = 0
path = rider["route"]
flags = rider["rider_flags"]
revenue = rider["Total_order_value"]*our_cut
for i in range(len(rider["rider_flags"])):
if flags[i] == 0:
cost = cost + calculate_distance([path[i]],[path[i+1]]) * first_mile_cost
elif flags[i] == 1:
cost = cost + calculate_distance([path[i]],[path[i+1]]) * last_mile_cost
elif flags[i] == -1:
cost = cost + calculate_distance([path[i]],[path[i+1]]) * return_mile_cost
else:
print("Invalid flag")
tot_profit = revenue - cost
return tot_profit
except Exception as e:
print(f"Error calculating profit: {e}")
return 0