Python 每次在for循环中调用函数时,该函数似乎运行得更快
我写了一个非常粗糙的爬山/贪婪算法来解决旅行推销员问题。其目的是将其用作基准,同时不断改进运行时间并优化解决方案 编辑:根据Stefan Pochmann的建议,这似乎与硬件有关,而与程序无关。在i7-4790处理器上,在开始爬山循环之前立即执行Python 每次在for循环中调用函数时,该函数似乎运行得更快,python,algorithm,Python,Algorithm,我写了一个非常粗糙的爬山/贪婪算法来解决旅行推销员问题。其目的是将其用作基准,同时不断改进运行时间并优化解决方案 编辑:根据Stefan Pochmann的建议,这似乎与硬件有关,而与程序无关。在i7-4790处理器上,在开始爬山循环之前立即执行sum(xrange(10**8))将导致第一次爬山的运行时间超过一半,并在每个循环上进一步提高。 如果我在循环中对相同的数据运行爬山算法10次(每次爬山进行10000次迭代),我注意到解决方案的运行时间几乎总是普遍下降,最终解决方案占用第一个解决方案所
sum(xrange(10**8))
将导致第一次爬山的运行时间超过一半,并在每个循环上进一步提高。
如果我在循环中对相同的数据运行爬山算法10次(每次爬山进行10000次迭代),我注意到解决方案的运行时间几乎总是普遍下降,最终解决方案占用第一个解决方案所需时间的约50%。在每个解上计算的唯一东西是爬山本身;支持数据(如距离/时间矩阵和作业列表)在所有解决方案之前存储在内存中。因此,前三个函数仅用于MCVE,可以忽略
打印的输出是运行时,然后是[(迭代次数,贪婪路径成本)]
列表,即搜索解决方案时选择新的最佳路径的迭代次数。运行时间似乎与每次爬山时存储的临时路线数无关。每个解决方案都应该是独立的。有人能在计算路线成本
或爬山
中看到加速的原因吗?我在这里遗漏了什么?我将如何分析这种加速的原因?这是在Python2.7.9中实现的
import math
import random
import datetime
# To generate a random customer name for each fake order
LETTERS = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q',
'r','s','t','u','v','w','x','y','z']
def crow_flies(lat1, lon1, lat2, lon2):
''' For MCVE. Straight-line distance between two locations. Should not affect
run time.
'''
dx1,dy1 = (lat1/180)*3.141593,(lon1/180)*3.141593
dx2,dy2 = (lat2/180)*3.141593,(lon2/180)*3.141593
dlat,dlon = abs(dx2-dx1),abs(dy2-dy1)
a = (math.sin(dlat/2))**2 + (math.cos(dx1) * math.cos(dx2)
* (math.sin(dlon/2))**2)
c = 2*(math.atan2(math.sqrt(a),math.sqrt(1-a)))
km = 6373 * c
return km
def gen_matrix(order_list):
''' For MCVE. Returns dictionary of distance and time between all
location pairs. Should not affect run time.
Returns {(location_id_from, location_id_to): [distance, time]}
'''
matrix = {}
for loc in order_list:
for pair_loc in order_list:
if loc[0] != pair_loc[0]:
distance = crow_flies(loc[1], loc[2], pair_loc[1], pair_loc[2])
matrix[(loc[0], pair_loc[0])] = [distance, distance*random.random()]
return matrix
def gen_jobs(num_jobs, start_time, end_time, lat_low, lat_high, lon_low, lon_high):
''' For MVCE. Creates random jobs with random time windows and locations
'''
job_list = []
for x in range(num_jobs):
lat = random.uniform(lat_low, lat_high)
lon = random.uniform(lon_low, lon_high)
start = random.randrange(start_time, end_time-120, 1)
end = start + 120
faux_start = random.randrange(start, end-60, 1)
faux_end = faux_start + 60
capacity_demand = random.choice([-1, 1])
name_1 = random.choice(LETTERS)
name_2 = random.choice(LETTERS)
name_3 = random.choice(LETTERS)
name_4 = random.choice(LETTERS)
name_5 = random.choice(LETTERS)
NAME = name_1 + name_2 + name_3 + name_4 + name_5
job_list.append([NAME, lat, lon, start, end, faux_start, faux_end,
capacity_demand])
return job_list
def calc_route_cost(start_time, route, matrix):
''' Returns the cost of each randomly generated route '''
cost = 0
# Mileage cost
dist_cost = sum([matrix[(route[x][0], route[x+1][0])][0] for x in
range(len(route)-1)]) * 0.14
cost += dist_cost
# Man-hour cost
time_cost = sum([matrix[(route[x][0], route[x+1][0])][1] for x in
range(len(route)-1)]) * 0.35
cost += time_cost
for x in range(0, len(route)-1):
travel_time = matrix[(route[x][0], route[x+1][0])][1]
arrival = start_time + travel_time
start_time += travel_time
departure = arrival + 10
if arrival < route[x+1][3]:
# Penalise early arrival
arr_cost = (route[x+1][3] - arrival)**2
cost += arr_cost
elif departure > route[x+1][4]:
# Penalise late departure
dep_cost = (departure - route[x+1][4])**2
cost += dep_cost
if arrival < route[x+1][5]:
# Penalise 'soft' early arrival i.e. earlier than a fake prediction
# of arrival
faux_arr_cost = (route[x+1][5] - arrival)**1.2
cost += faux_arr_cost
elif departure > route[x+1][6]:
# Penalise 'soft' late departure
faux_dep_cost = (departure - route[x+1][6])**1.2
cost += faux_dep_cost
return cost
def hill_climb(jobs, matrix, iterations):
''' Randomly generate routes and store route if cheaper than predecessor '''
cost_tracking, iteration_track = [], []
initial_cost = calc_route_cost(480, jobs, matrix)
best_cost = initial_cost
best_route = jobs[:]
changed_route = jobs[:]
for x in range(iterations):
random.shuffle(changed_route)
new_cost = calc_route_cost(480, changed_route, matrix)
if new_cost < best_cost:
best_route = changed_route[:]
best_cost = new_cost
cost_tracking.append(best_cost)
iteration_track.append(x)
return cost_tracking, iteration_track
if __name__ == '__main__':
#random_jobs = gen_jobs(20, 480, 1080, 24, 25, 54, 55)
random_jobs = [['lmizn', 24.63441343319078, 54.766698677134784, 501, 621, 558, 618, 1],
['jwrmk', 24.45711393348282, 54.255786174435165, 782, 902, 782, 842, 1],
['gbzqc', 24.967074991405035, 54.07326911656665, 682, 802, 687, 747, 1],
['odriz', 24.54161147027789, 54.13774173532877, 562, 682, 607, 667, -1],
['majfj', 24.213785557876257, 54.452603867220475, 681, 801, 731, 791, -1],
['scybg', 24.936517492880274, 54.83786889438055, 645, 765, 662, 722, -1],
['betow', 24.78072704532661, 54.99907581479066, 835, 955, 865, 925, -1],
['jkhmp', 24.88461478479374, 54.42327833917202, 546, 666, 557, 617, -1],
['wbpnq', 24.328080543462, 54.85565694610073, 933, 1053, 961, 1021, -1],
['ezguc', 24.292203133848382, 54.65239508177714, 567, 687, 583, 643, -1],
['nlbgh', 24.111932340385735, 54.895627940055995, 675, 795, 711, 771, -1],
['rtmbc', 24.64381176454049, 54.739636798961044, 870, 990, 910, 970, 1],
['znkah', 24.235361720889216, 54.699010081109854, 627, 747, 645, 705, -1],
['yysai', 24.48931405352803, 54.37480185313546, 870, 990, 882, 942, -1],
['mkmbk', 24.5628992946158, 54.219159859450926, 833, 953, 876, 936, -1],
['wqygy', 24.035376675509728, 54.92994438408514, 693, 813, 704, 764, -1],
['gzwwa', 24.476121543580852, 54.13822533413381, 854, 974, 879, 939, 1],
['xuyov', 24.288078529689894, 54.81812092976614, 933, 1053, 935, 995, 1],
['tulss', 24.841925420359246, 54.08156783033599, 670, 790, 684, 744, -1],
['ptdng', 24.113767467325335, 54.9417036320267, 909, 1029, 941, 1001, 1]]
matrix = gen_matrix(random_jobs)
# Below is the loop that appears to accelerate
for p in range(10):
start = datetime.datetime.now()
sim_ann = hill_climb(random_jobs, matrix, 10000)
end = datetime.datetime.now()
# Number of iterations against greedy cost
iteration_count = zip(sim_ann[1], sim_ann[0])
print 'RUNTIME:', str(end - start)
print 'SOLUTION CONVERGENCE:', str(iteration_count)
导入数学
随机输入
导入日期时间
#为每个假订单生成随机客户名称
字母=['a'、'b'、'c'、'd'、'e'、'f'、'g'、'h'、'i'、'j'、'k'、'l'、'm'、'n'、'o'、'p'、'q',
‘r’、‘s’、‘t’、‘u’、‘v’、‘w’、‘x’、‘y’、‘z’]
def乌鸦蝇(lat1、lon1、lat2、lon2):
“给麦克维。两个位置之间的直线距离。不应影响
运行时。
'''
dx1,dy1=(lat1/180)*3.141593,(lon1/180)*3.141593
dx2,dy2=(lat2/180)*3.141593,(lon2/180)*3.141593
dlat,dlon=abs(dx2-dx1),abs(dy2-dy1)
a=(math.sin(dlat/2))**2+(math.cos(dx1)*math.cos(dx2)
*(数学单(dlon/2))**2)
c=2*(数学atan2(数学sqrt(a),数学sqrt(1-a)))
公里=6373*c
返回公里
def gen_矩阵(订单列表):
“给麦克维。返回所有对象之间的距离和时间字典
位置对。不应影响运行时。
返回{(location_id_from,location_id_to):[distance,time]}
'''
矩阵={}
对于订单列表中的loc:
对于订单列表中的配对位置:
如果loc[0]!=配对位置[0]:
距离=乌鸦(位置[1],位置[2],成对位置[1],成对位置[2])
矩阵[(loc[0],pair_loc[0])]=[距离,距离*随机。随机()
返回矩阵
def gen_作业(数量作业、开始时间、结束时间、纬度低、纬度高、纬度低、纬度高):
“给MVCE。创建具有随机时间窗口和位置的随机作业
'''
作业列表=[]
对于范围内的x(num_作业):
横向=随机均匀(横向低,横向高)
lon=随机均匀(lon_低,lon_高)
开始=随机。随机范围(开始时间,结束时间-120,1)
结束=开始+120
faux_start=random.randrange(开始,结束-60,1)
人造终点=人造起点+60
容量需求=随机选择([-1,1])
name_1=随机选择(字母)
name_2=随机选择(字母)
name_3=随机选择(字母)
name_4=随机选择(字母)
name_5=随机选择(字母)
姓名=姓名1+姓名2+姓名3+姓名4+姓名5
作业列表。追加([名称、纬度、经度、起点、终点、假起点、假终点、,
容量(单位需求量)
返回作业列表
def计算路线成本(开始时间、路线、矩阵):
''返回每个随机生成路由的成本''
成本=0
#里程成本
dist_cost=x in的总和([matrix[(route[x][0],route[x+1][0])][0]
范围(长度(路线)-1)]*0.14
成本+=距离成本
#工时费
时间成本=x英寸的总和([矩阵[(路径[x][0],路径[x+1][0])][1]
范围(长度(路线)-1)]*0.35
成本+=时间成本
对于范围内的x(0,透镜(路线)-1):
行程时间=矩阵[(路线[x][0],路线[x+1][0])][1]
到达=开始时间+旅行时间
开始时间+=行程时间
出发=到达+10
如果到达<路线[x+1][3]:
#惩罚提前到达
到达成本=(路线[x+1][3]-到达)**2
成本+=到货成本
elif出发>路线[x+1][4]:
#处罚迟到
dep_成本=(出发-路线[x+1][4])**2
成本+=折旧成本
如果到达<路线[x+1][5]:
#惩罚“软”提前到达,即早于虚假预测
#到达时间
人工到达成本=(路线[x+1][5]-到达)**1.2
成本+=人造成本
elif出发>路线[x+1][6]:
#处罚“软性”迟到
假折旧成本=(出发-路线[x+1][6])**1.2
成本+=假折旧成本
退货成本
def爬山(作业、矩阵、迭代):
''随机生成路由并存储路由(如果比前一个路由便宜''
成本跟踪,迭代跟踪=[],[]
初始成本=计算路线成本(480,作业,矩阵)
最佳成本=初始成本
最佳路径=作业[:]
更改的路径=作业[:]
对于范围内的x(迭代):
随机。洗牌(改变路线)
新成本=计算路线成本(480,变更路线,矩阵)
如果新成本<最佳成本:
最佳路线=更改的路线[:]
最佳成本=新成本
成本跟踪。追加(最佳成本)
迭代_track.append(x)
退货成本
for x in range(10):
a = sum(xrange(10**8))