Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
Abhishek K. Umrawal Final Reorganization.
Latest commit d38b448 Jan 23, 2020 History
2 contributors

Users who have contributed to this file

@singh596 @aumrawal-purdue
executable file 363 lines (299 sloc) 13.7 KB
# coding: utf-8
# In[ ]:
import numpy as np
import pandas as pd
from pathgenerator import PathGenerator
import geohelper as gh
import geohash2 as Geohash
TIMESTEP = 60
GEOHASH_PRECISION = 7
REJECT_DISTANCE = 7000
# SERVICE_REWARD = RIDE_REWARD + TRIP_REWARD * trip_time - WAIT_COST * wait_time
RIDE_REWARD = 10.0 #5,6,7,8,9,10
TRIP_REWARD = 1.0
WAIT_COST = 0.05
HOP_REWARD = 3.5
MIN_TRIPTIME = 1.0 # in meters
ASSIGNMENT_SPEED = 50 # km/h (grand circle distance)
def index_pull(rows,trips_test_2):
val= trips_test_2[(trips_test_2['plat']==rows['plat'].item()) & (trips_test_2['plon']==rows['plon'].item())].index.values
return val
class FleetSimulator(object):
"""
FleetSimulator is an environment in which fleets mobility, dispatch
and passenger pickup / dropoff are simulated.
"""
def __init__(self, G, eta_model, cycle, max_action_time=15):
self.router = PathGenerator(G)
self.eta_model = eta_model
self.cycle = cycle
self.max_action_time = max_action_time
def reset(self, num_vehicles, dataset, dayofweek, minofday):
self.requests = dataset
self.current_time = 0
self.minofday = minofday
self.dayofweek = dayofweek
init_locations = self.requests[['plat', 'plon']].values[np.arange(num_vehicles) % len(self.requests)]
self.vehicles = [Vehicle(i, init_locations[i]) for i in range(num_vehicles)]
def update_time(self):
self.current_time += TIMESTEP
self.minofday += int(TIMESTEP / 60.0)
if self.minofday >= 1440:
self.minofday -= 1440
self.dayofweek = (self.dayofweek + 1) % 7
def step(self, actions=None):
"""
step forward the environment by TIMESTEP
"""
num_steps = int(self.cycle * 60.0 / TIMESTEP)
if actions:
self.dispatch(actions)
requests = self.get_requests(num_steps)
wait, reject, gas,request_hop_zero = 0, 0, 0, 0
for _ in range(num_steps):
for vehicle in self.vehicles:
gas += vehicle.transition()
X = self.get_vehicles_location()
W = requests[(requests.second >= self.current_time)
&(requests.second < self.current_time + TIMESTEP)]
assignments = self.match(X, W)
wait_,num_vehicles,num_passengers,request_hop_zero_ = self.assign(assignments)
wait += wait_
assignment_length = len(assignments)
reject += len(W) - num_passengers
request_hop_zero += request_hop_zero_
self.update_time()
vehicles = self.get_vehicles_dataframe()
return vehicles, requests, wait, reject, gas, request_hop_zero
def get_requests(self, num_steps, offset=0):
requests = self.requests[(self.requests.second >= self.current_time + offset * TIMESTEP)
&(self.requests.second < self.current_time + TIMESTEP * (num_steps + offset))]
return requests
def get_vehicles_dataframe(self):
vehicles = [vehicle.get_state() for vehicle in self.vehicles]
vehicles = pd.DataFrame(vehicles, columns=['id', 'available', 'geohash', 'dest_geohash',
'eta', 'status', 'reward', 'lat', 'lon', 'idle','eff_dist','act_dist'])
return vehicles
def get_vehicles_location(self):
vehicles = [vehicle.get_location() for vehicle in self.vehicles]
vehicles = pd.DataFrame(vehicles, columns=['id', 'lat', 'lon', 'available'])
return vehicles
def get_vehicles_score(self):
vehicles = [vehicle.get_score() for vehicle in self.vehicles]
vehicles = pd.DataFrame(vehicles, columns=['id', 'reward', 'service_time', 'idle_time'])
return vehicles
def match(self, resources, tasks):
#non_hop_tasks = tasks[tasks['hop_flag']==0]
#non_hop_tasks_col = non_hop_tasks['plat','plon']
#hop_tasks = tasks[tasks['hop_flag']==1]
R = resources[resources.available == 1]
tasks_uniq = tasks.groupby(['plat','plon']).count()
tasks_uniq = tasks_uniq.reset_index(level=['plat','plon'])
tasks_uniq = tasks_uniq[['plat','plon']]
tasks_uniq['index']=tasks_uniq.apply(lambda rows:tasks[(tasks['plat']==rows['plat'].item()) &
(tasks['plon']==rows['plon'].item())].index.values , axis=1)
d = gh.distance_in_meters(R.lat.values,
R.lon.values,
tasks_uniq.plat.values[:, None],
tasks_uniq.plon.values[:, None])
N = min(len(tasks_uniq), len(R))
vids = np.zeros(N, dtype=int)
for i in range(N):
vid = d[i].argmin()
if d[i, vid] > REJECT_DISTANCE:
vids[i] = -1
else:
vids[i] = vid
d[:, vid] = float('inf')
index_values = tasks_uniq.index[:N][vids >= 0]
#trips_indices = tasks.loc[index_values]['index']
assignments = list(zip(tasks_uniq.loc[index_values]['index'], R['id'].iloc[vids[vids >= 0]]))
#assignments = zip(tasks.index[:N][vids >= 0], R['id'].iloc[vids[vids >= 0]])
return assignments
def assign(self, assignments):
"""
assign ride requests to selected vehicles
"""
num_vehicles = len(assignments)
request_hop_zero =0
num_passengers = 0
wait = 0
effective_d = 0
actual_d =0
for r, v in assignments:
vehicle = self.vehicles[v] # pointer to a Vehicle object
request = self.requests.loc[r]
num_present_vehicle_pass = len(request)
request_hop_zero += sum(request['hop_flag']==0)
num_passengers += num_present_vehicle_pass
request_sort = request.sort_values(by=['trip_time'])
first_row = request_sort.iloc[0]
last_row = request_sort.iloc[-1]
#print (last_row)
ploc = (first_row.plat, first_row.plon)
dloc = (last_row.dlat, last_row.dlon)
#dloc = (last_row.dlat, last_row.dlon)
vloc = vehicle.location
#print (vloc[0], vloc[1], ploc[0], ploc[1])
d = gh.distance_in_meters(vloc[0], vloc[1], ploc[0], ploc[1])
# wait_time = 1 + d / (ASSIGNMENT_SPEED * 1000 / 60)
wait_time = (d * 2 / 1.414) / (ASSIGNMENT_SPEED * 1000 / 60)
#print (d)
##calculation for the trip time , effective distance, total distance
eff_distance = sum(request.trip_distance)
request_sort_copy = request_sort.copy()
request_sort.loc[:,'index_val'] = range(len(request_sort))
request_sort_copy.loc[:,'index_val'] = request_sort['index_val'].values -1
request_sort_copy = request_sort_copy[['dlat','dlon','index_val']]
request_sort_join = pd.merge(request_sort, request_sort_copy, how='left', on=None, left_on='index_val', right_on='index_val',
left_index=False, right_index=False, sort=False,suffixes=('_x', '_y'),
copy=True, indicator=False,validate=None)
request_join_no_na = request_sort_join.dropna()
#print (len(request_join_no_na))
#print (request_)
#request_join_no_na['dist_bw_dest'] = gh.distance_in_meters(request_join_no_na.dlat_x,request_join_no_na.dlon_x,
# request_join_no_na.dlat_y,request_join_no_na.dlon_y)
if len(request_join_no_na) > 0:
request_join_no_na['dist_bw_dest'] = gh.distance_in_meters(request_join_no_na.dlat_x,request_join_no_na.dlon_x,
request_join_no_na.dlat_y,request_join_no_na.dlon_y)
actual_distance = first_row.trip_distance + (sum(request_join_no_na.dist_bw_dest))/1000
trip_time = (actual_distance/ASSIGNMENT_SPEED)*60
#print ('shared....')
#print (type(actual_distance),type(trip_time))
#print (trip_time)
else:
actual_distance = first_row.trip_distance
trip_time = first_row.trip_time
#print ('not shared....')
#print (type(actual_distance),type(trip_time))
#print (trip_time)
#trip_time = request.trip_time
vehicle.start_service(dloc, wait_time, trip_time,actual_distance,eff_distance,num_present_vehicle_pass)
wait += wait_time
# effective_d +=eff_distance
# actual_d += actual_distance
return wait,num_vehicles,num_passengers,request_hop_zero
def dispatch(self, actions):
cache = []
distances = []
vids, targets = zip(*actions)
vlocs = [self.vehicles[vid].location for vid in vids]
for vloc, tloc in zip(vlocs, targets):
try:
p, d, s, t = self.router.map_matching_shortest_path(vloc, tloc)
cache.append((p, s, t))
distances.append(d)
except:
start_lat = vloc[0]
start_lon = vloc[1]
dest_lat = tloc[0]
dest_lon = tloc[1]
d = gh.distance_in_meters(start_lat,start_lon, dest_lat,dest_lon)
distances.append(d)
N = len(vids)
X = np.zeros((N, 7))
X[:, 0] = self.dayofweek
X[:, 1] = self.minofday / 60.0
X[:, 2:4] = vlocs
X[:, 4:6] = targets
X[:, 6] = distances
trip_times = self.eta_model.predict(X)
for i, vid in enumerate(vids):
if trip_times[i] > MIN_TRIPTIME:
#p, s, t = cache[i]
#step = distances[i] / (trip_times[i] * 60.0 / TIMESTEP)
#trajectory = self.router.generate_path(vlocs[i], targets[i], step, p, s, t)
eta = min(trip_times[i], self.max_action_time)
self.vehicles[vid].route([], eta)
return
class Vehicle(object):
"""
Status available location eta storage_id
WT: waiting 1 real 0 0
MV: moving 1 real >0 0
SV: serving 0 future >0 0
ST: stored 0 real 0 >0
CO: carry-out 0 real >0 r>0
"""
def __init__(self, vehicle_id, location):
self.id = vehicle_id
self.status = 'WT'
self.location = location
self.zone = Geohash.encode(location[0], location[1], precision=GEOHASH_PRECISION)
self.available = True
self.trajectory = []
self.eta = 0
self.idle = 0
self.total_idle = 0
self.total_service = 0
self.reward = 0
self.effective_d =0
self.actual_d = 0
def update_location(self, location):
lat, lon = location
self.location = (lat, lon)
self.zone = Geohash.encode(lat, lon, precision=GEOHASH_PRECISION)
def transition(self):
cost = 0
if self.status != 'SV':
self.idle += TIMESTEP/60.0
if self.eta > 0:
time = min(TIMESTEP/60.0, self.eta)
self.eta -= time
# moving
#if self.trajectory:
if self.status == 'MV':
#self.update_location(self.trajectory.pop(0))
cost = time
self.reward -= cost
if self.eta <= 0:
# serving -> waiting
if self.status == 'SV':
self.available = True
self.status = 'WT'
# moving -> waiting
elif self.status == 'MV':
self.status = 'WT'
return cost
def start_service(self, destination, wait_time, trip_time,actual_distance,eff_distance,num_pass):
#print (type(wait_time))
#print (type(trip_time))
#print type(destination)
if not self.available:
print ("The vehicle #%d is not available for service." % self.id)
return False
self.available = False
self.update_location(destination)
self.total_idle += self.idle + wait_time
num_hops = eff_distance /actual_distance
self.idle = 0
self.eta = wait_time + trip_time
self.total_service += trip_time
self.reward += RIDE_REWARD*num_pass + TRIP_REWARD * trip_time - WAIT_COST * wait_time - HOP_REWARD*num_hops
self.trajectory = []
self.status = 'SV'
self.effective_d += eff_distance
self.actual_d +=actual_distance
return True
def route(self, path, trip_time):
if not self.available:
print ("The vehicle #%d is not available for service." % self.id)
return False
self.eta = trip_time
self.trajectory = path
self.status = 'MV'
return True
def get_state(self):
if self.trajectory:
lat, lon = self.trajectory[-1]
dest_zone = Geohash.encode(lat, lon, precision=GEOHASH_PRECISION)
else:
dest_zone = self.zone
lat, lon = self.location
return (self.id, int(self.available), self.zone, dest_zone,
self.eta, self.status, self.reward, lat, lon, self.idle,self.effective_d,self.actual_d)
def get_location(self):
lat, lon = self.location
return (self.id, lat, lon, int(self.available))
def get_score(self):
return (self.id, self.reward, self.total_service, self.total_idle)