def search_direction_multi(f, graphs, gs, ods, L, grad): # extension of search_direction routine in frank_wolfe_2.py # for the heterogeneous game #start timer start_time1 = timeit.default_timer() links = graphs[0].shape[0] types = len(graphs) for j, (graph, g, od) in enumerate(zip(graphs, gs, ods)): #start timer start_time2 = timeit.default_timer() l, gr = search_direction(np.sum(np.reshape(f,(types,links)).T,1), \ graph, g, od) #end of timer #elapsed2 = timeit.default_timer() - start_time2; #print ("step0 too %s seconds" % elapsed1) L[(j*links) : ((j+1)*links)] = l grad[(j*links) : ((j+1)*links)] = gr #end of timer #elapsed1 = timeit.default_timer() - start_time1; #print ("Search_direction for all pairs: %s seconds" % elapsed1) return L, grad
def search_direction_multi(f, graphs, gs, ods, L, grad): # extension of search_direction routine in frank_wolfe_2.py # for the heterogeneous game links = graphs[0].shape[0] types = len(graphs) for j, (graph, g, od) in enumerate(zip(graphs, gs, ods)): l, gr = search_direction(np.sum(np.reshape(f, (types, links)).T, 1), graph, g, od) L[(j * links):((j + 1) * links)] = l grad[(j * links):((j + 1) * links)] = gr return L, grad
def search_direction_multi(f, graphs, gs, ods, L, grad): # extension of search_direction routine in frank_wolfe_2.py # for the heterogeneous game links = graphs[0].shape[0] types = len(graphs) for j, (graph, g, od) in enumerate(zip(graphs, gs, ods)): l, gr = search_direction(np.sum(np.reshape(f,(types,links)).T,1), \ graph, g, od) L[(j*links) : ((j+1)*links)] = l grad[(j*links) : ((j+1)*links)] = gr return L, grad
def fw_heterogeneous_2(graphs, demands, past=10, max_iter=100, eps=1e-8, q=50, display=0, stop=1e-8): ''' Frank-Wolfe algorithm on the heterogeneous game given a list of graphs in the format g = [[link_id from to a0 a1 a2 a3 a4]] and demand in the format d = [[o d flow]] ''' assert past <= q, "'q' must be bigger or equal to 'past'" # construct graph and demand objects suiteable for AoN_igraph gs = [construct_igraph(graph) for graph in graphs] ods = [construct_od(demand) for demand in demands] # construct empty vector to be filled in with values links = graphs[0].shape[0] types = len(graphs) # initial flow assignment is null f = np.zeros(links * types, dtype="float64") fs = np.zeros((links * types, past), dtype="float64") L = np.zeros(links * types, dtype="float64") grad = np.zeros(links * types, dtype="float64") L2 = np.zeros(links * types, dtype="float64") grad2 = np.zeros(links * types, dtype="float64") error = 'N/A' # compute re-normalization constant K = sum([total_free_flow_cost(g, od) for g, od in zip(gs, ods)]) if K < eps: K = sum([np.sum(demand[:, 2]) for demand in demands]) elif display >= 1: print 'average free-flow travel time', \ K / sum([np.sum(demand[:, 2]) for demand in demands]) # compute iterations for i in range(max_iter): if display >= 1: print 'iteration: {}, error: {}'.format(i + 1, error) # construct weighted graph with latest flow assignment # print 'f', f # print 'reshape', np.reshape(f,(links,types)) total_f = np.sum(np.reshape(f, (types, links)).T, 1) # print 'total flow', total_f for j, (graph, g, od) in enumerate(zip(graphs, gs, ods)): l, gr = search_direction(total_f, graph, g, od) L[(j * links):((j + 1) * links)] = l grad[(j * links):((j + 1) * links)] = gr # print 'L', L # print 'grad', grad fs[:, i % past] = L w = L - f if i >= 1: error = -grad.dot(w) / K # if error < stop and error > 0.0: if error < stop: if display >= 1: print 'stop with error: {}'.format(error) return np.reshape(f, (types, links)).T if i > q: # step 3 of Fukushima v = np.sum(fs, axis=1) / min(past, i + 1) - f norm_v = np.linalg.norm(v, 1) if norm_v < eps: if display >= 1: print 'stop with norm_v: {}'.format(norm_v) return np.reshape(f, (types, links)).T norm_w = np.linalg.norm(w, 1) if norm_w < eps: if display >= 1: print 'stop with norm_w: {}'.format(norm_w) return np.reshape(f, (types, links)).T # step 4 of Fukushima gamma_1 = grad.dot(v) / norm_v gamma_2 = grad.dot(w) / norm_w if gamma_2 > -eps: if display >= 1: print 'stop with gamma_2: {}'.format(gamma_2) return np.reshape(f, (types, links)).T d = v if gamma_1 < gamma_2 else w # step 5 of Fukushima s = line_search( lambda a: merit(f + a * d, graphs, gs, ods, L2, grad2)) # print 'step', s if s < eps: if display >= 1: print 'stop with step_size: {}'.format(s) return np.reshape(f, (types, links)).T f = f + s * d else: f = f + 2. * w / (i + 2.) return np.reshape(f, (types, links)).T
# used to keep track of iteration for indexing in path_flow_* default dicts index = 0 for alpha in np.linspace(0, 1, granularity): with open('{}/LA_net_od_2_alpha_{}.txt'.format(in_folder, alpha), 'r') as infile: run = pickle.loads(infile.read()) fs = run['f'] f = np.array([l[0] + l[1] for l in fs]) tt = (graph[:, 3] + graph[:, 7] * f**4) / 60 tts += [tt] if calculate_nd: g = construct_igraph(graph) L, grad, path_flows = search_direction(f, graph, g, od) nd = np.dot(tt, f - L) nds += [nd] print nd # produce OD data json needed for dashboard if make_dash_data: od_paths = {} od2id = {} path2id = {} for k in run['h'].keys(): odp = (k[0], k[1]) if odp not in od2id: od2id[odp] = len(od2id) if od2id[odp] not in od_paths:
def fw_heterogeneous_2(graphs, demands, past=10, max_iter=100, eps=1e-8, q=50, \ display=0, stop=1e-8): ''' Frank-Wolfe algorithm on the heterogeneous game given a list of graphs in the format g = [[link_id from to a0 a1 a2 a3 a4]] and demand in the format d = [[o d flow]] ''' assert past <= q, "'q' must be bigger or equal to 'past'" # construct graph and demand objects suiteable for AoN_igraph gs = [construct_igraph(graph) for graph in graphs] ods = [construct_od(demand) for demand in demands] # construct empty vector to be filled in with values links = graphs[0].shape[0] types = len(graphs) f = np.zeros(links*types,dtype="float64") # initial flow assignment is null fs = np.zeros((links*types,past),dtype="float64") L = np.zeros(links*types,dtype="float64") grad = np.zeros(links*types,dtype="float64") L2 = np.zeros(links*types,dtype="float64") grad2 = np.zeros(links*types,dtype="float64") # compute re-normalization constant K = sum([total_free_flow_cost(g, od) for g,od in zip(gs, ods)]) if K < eps: K = sum([np.sum(demand[:,2]) for demand in demands]) elif display >= 1: print 'average free-flow travel time', \ K / sum([np.sum(demand[:,2]) for demand in demands]) # compute iterations for i in range(max_iter): if display >= 1: if i <= 1: print 'iteration: {}'.format(i+1) else: print 'iteration: {}, error: {}'.format(i+1, error) # construct weighted graph with latest flow assignment #print 'f', f #print 'reshape', np.reshape(f,(links,types)) total_f = np.sum(np.reshape(f,(types,links)).T,1) #print 'total flow', total_f for j, (graph, g, od) in enumerate(zip(graphs, gs, ods)): l, gr = search_direction(total_f, graph, g, od) L[(j*links) : ((j+1)*links)] = l grad[(j*links) : ((j+1)*links)] = gr #print 'L', L #print 'grad', grad fs[:,i%past] = L w = L - f if i >= 1: error = -grad.dot(w) / K # if error < stop and error > 0.0: if error < stop: if display >= 1: print 'stop with error: {}'.format(error) return np.reshape(f,(types,links)).T if i > q: # step 3 of Fukushima v = np.sum(fs,axis=1) / min(past,i+1) - f norm_v = np.linalg.norm(v,1) if norm_v < eps: if display >= 1: print 'stop with norm_v: {}'.format(norm_v) return np.reshape(f,(types,links)).T norm_w = np.linalg.norm(w,1) if norm_w < eps: if display >= 1: print 'stop with norm_w: {}'.format(norm_w) return np.reshape(f,(types,links)).T # step 4 of Fukushima gamma_1 = grad.dot(v) / norm_v gamma_2 = grad.dot(w) / norm_w if gamma_2 > -eps: if display >= 1: print 'stop with gamma_2: {}'.format(gamma_2) return np.reshape(f,(types,links)).T d = v if gamma_1 < gamma_2 else w # step 5 of Fukushima s = line_search(lambda a: merit(f+a*d, graphs, gs, ods, L2, grad2)) # print 'step', s if s < eps: if display >= 1: print 'stop with step_size: {}'.format(s) return np.reshape(f,(types,links)).T f = f + s*d else: f = f + 2. * w/(i+2.) return np.reshape(f,(types,links)).T