def dijkstra_travel_cost(self, r): # r is the destination. TEST = int(open_config_file('test_Graph')) unlabeled_nodes = set() travel_cost = [] sequence = [] # Initialzie nodes and travel_cost. for i in range(self.V): unlabeled_nodes.add(i) travel_cost.append(float('inf')) sequence.append(float('inf')) # Destination has travel_cost 0. travel_cost[r] = 0 # Used to update sequence. count = 0 while unlabeled_nodes: # Find the node with smallest travel_cost label in unlabeled nodes set. min_travel_cost = float('inf') min_node = float('inf') for i in unlabeled_nodes: if travel_cost[i] < min_travel_cost: min_travel_cost = travel_cost[i] min_node = i # Remove this node from the unlabeled list, namely finalize the travel_cost. if min_node != float('inf'): unlabeled_nodes.remove(min_node) # If remaining unlabeled nodes are not connected with current destination ... # break out of loop. else: break # Update the travel_cost of upstream nodes of min_node. # Note: use link travel cost. incoming_links = [ item for item in self.links if item[3] == min_node ] for item in incoming_links: if travel_cost[item[2]] > travel_cost[min_node] + item[8]: travel_cost[item[2]] = travel_cost[min_node] + item[8] sequence[item[2]] = count count += 1 return travel_cost, sequence
# This scrpt can convert the OD flows and proportion matrix obtained from the # schedule-based assignment model into measurements. import numpy as np import sys from TimeExpandedNetwork import TimeExpandedNetwork from open_config_file import open_config_file from open_data_file_with_header import open_data_file_with_header tn = TimeExpandedNetwork() T = int(open_config_file('HORIZON')) # Parameters DISPLAY_PROGRESS = int(open_config_file('DISPLAY_PROGRESS')) # Number of stops N = len(tn.stops) # Periods of measurements (Unit: min) C = int(open_config_file('MEASUREMENT_PERIOD')) # Times of measurements K = int(T / C) # Input: OD flows od_flow = np.load('data/od_flow.npy') # Input: proportions od_flow_to_stop_prob = np.load('data/od_flow_to_stop_prob.npy') link_combined_flow = np.load('data/link_combined_flow.npy')
def dijkstra_arrival_time(self, r): # r is the destination. TEST = int(open_config_file('test_Graph')) unlabeled_nodes = set() arrival_time = [] sequence = [] # Initialzie nodes and arrival_time. for i in range(self.V): unlabeled_nodes.add(i) arrival_time.append(float('inf')) sequence.append(float('inf')) # Destination has arrival_time 0. arrival_time[r] = 0 # Used to update sequence. count = 0 while unlabeled_nodes: # Find the node with smallest arrival_timeance label in unlabeled nodes set. min_arrival_time = float('inf') min_node = float('inf') for i in unlabeled_nodes: if arrival_time[i] < min_arrival_time: min_arrival_time = arrival_time[i] min_node = i # Remove this node from the unlabeled list, namely finalize the arrival_time. if min_node != float('inf'): unlabeled_nodes.remove(min_node) # If all remaining unlabeled nodes are not connected with current destination ... # break out of loop. else: break # Update the arrival_time of upstream nodes of min_node incoming_links = [ item for item in self.links if item[3] == min_node ] for item in incoming_links: if item[4] == 'Dummy': # This link connect to destination; the arrival time equals # the time of this node. arrival_time[item[2]] = self.stops_exp_2[item[2]][2] sequence[item[2]] = count count += 1 else: # If the arrival time of the end of this link has NOT been made pernament. if arrival_time[item[2]] == float('inf'): arrival_time[item[2]] = arrival_time[min_node] sequence[item[2]] = count count += 1 return arrival_time, sequence
def static_model(sn): """Input StaticNetwork obj; output UE assignment results into files.""" # sn: static network object. print(' ------------------------------------------------------------------------------') print(" Static model begins ...") # Total number of stops num_stops = len(sn.stops) num_stops_exp = len(sn.stops_exp) # 'exp' means expanded num_ods = num_stops ** 2 num_links = len(sn.links) num_links_exp = len(sn.links_exp) MAX_NUMBER_OF_ITERATIONS = int(open_config_file('MAX_NUMBER_OF_ITERATIONS_FOR_BILEVEL_MODEL')) CONVERGENCE_CRITERION = float(open_config_file('CONVERGENCE_CRITERION_FOR_BILEVEL_MODEL')) TEST_STATIC_MODEL = float(open_config_file('test_static_model')) TRANSIT_TYPE = open_config_file('TRANSIT_TYPE') od_flow = np.zeros((num_stops,num_stops)) od_flow_vector = np.zeros(num_ods) # Input Data # Count data and covariance matrices. entry_count = np.zeros((num_stops,1)) exit_count = np.zeros((num_stops,1)) wifi_count = np.zeros((num_stops,1)) passby_count = np.zeros((num_stops,1)) # Retain only data column. entry_count_file = open_data_file_with_header('data/entry_count_by_hour.csv') exit_count_file = open_data_file_with_header('data/exit_count_by_hour.csv') wifi_count_file = open_data_file_with_header('data/wifi_count_by_hour.csv') for i_stop in range(num_stops): entry_count[i_stop,0] = float(entry_count_file[i_stop][1]) exit_count[i_stop,0] = float(exit_count_file[i_stop][1]) wifi_count[i_stop,0] = float(wifi_count_file[i_stop][1]) # Convert wifi count to stop count wifi_sample_ratio = open_data_file_with_header('data/wifi_sample_ratio.csv') # File header: # 0 # sample_ratio wifi_sample_ratio = [item[0] for item in wifi_sample_ratio] passby_count = np.zeros((num_stops,1)) for i_stop in range(num_stops): passby_count[i_stop,0] = wifi_count[i_stop,0] / float(wifi_sample_ratio[i_stop]) if TEST_STATIC_MODEL == 1: print(" entry_count:") print(entry_count) print(" exit_count:") print(exit_count) print(" passby_count:") print(passby_count) # Prepare coefficients for solve quadratic programming: # The composition of decision variable vector: # [od_flow_vector enter_flow exit_flow stop_flow] # which correspond to follwoing symboles in the paper: # [q O D x ] # Measurements will be denoted by: # [od_prior entry_count exit_count passby_count] # dimension = num_ods + 3 * num_stops # Coefficients: Q,p,A,b # Q Q = np.zeros((num_ods + 3 * num_stops, num_ods + 3 * num_stops)) for temp_index in range(num_ods, num_ods + 3 * num_stops): Q[temp_index, temp_index] = 2 # p temp = np.zeros((num_ods,1)) p = (-2) * np.concatenate((temp, entry_count, exit_count, passby_count), axis=0) del temp, entry_count, exit_count, wifi_count, passby_count # A A11 = np.zeros((num_stops,num_ods)) for n in range( num_stops): A11[n, n * num_stops : (n + 1) * num_stops] = np.ones((1,num_stops)) A12 = (-1) * np.identity(num_stops) A13 = np.zeros((num_stops,num_stops)) A14 = np.zeros((num_stops,num_stops)) A1 = np.concatenate((A11, A12, A13, A14), axis=1) del A11, A12, A13, A14 # A21 A21 = np.zeros((num_stops,num_ods)) for n1 in range(num_stops): for n2 in range(num_stops): A21[n1, num_stops * n2 + n1] = 1 A22 = np.zeros((num_stops,num_stops)) A23 = (-1) * np.identity(num_stops) A24 = np.zeros((num_stops,num_stops)) A2 = np.concatenate((A21, A22, A23, A24), axis=1) del A21, A22, A23, A24 A1_A2 = np.concatenate((A1, A2), axis=0) del A1, A2 # A31 will change during each iteration # A31 = od_flow_vector_to_stop_prob A32 = np.zeros((num_stops,num_stops)) A33 = np.zeros((num_stops,num_stops)) A34 = (-1) * np.identity(num_stops) A32_A33_A34 = np.concatenate((A32, A33, A34), axis=1) del A32, A33, A34 # b b = np.zeros(( 3 * num_stops, 1)) # G G = (-1) * np.identity(num_ods + 3 * num_stops) # h h = np.zeros((num_ods + 3 * num_stops, 1)) # Transform numpy matrices to cvxopt matrices Q = matrix(Q, tc='d') p = matrix(p, tc='d') G = matrix(G, tc='d') h = matrix(h, tc='d') b = matrix(b, tc='d') print() print(' Bi-level programming iteration begins...') # Bi-level programming iterations # Initialization iteration_count = 1 converg_flag = 0 # While convergence or maximum, iteration not reached, continue to loop while converg_flag == 0: print() print(' The ' + str(iteration_count) + '-th iteration of bi-level programming begins.') print() print(' Upper level begins ...') # Initialize the cost of network obj. for a_link in range(len(sn.links_exp)): if sn.links_exp[a_link][4] == TRANSIT_TYPE: sn.links_exp[a_link][8] = sn.links_exp[a_link][5] # Upper level if iteration_count == 1: # Initialization # Input very small od_flow to get od_flow_vector_to_stop_prob. od_flow = np.ones((num_stops, num_stops)) od_flow_vector_to_stop_prob = static_assignment_algorithm(sn, od_flow) # Adopt od_flow_vector_to_stop_prob matrix from assignment of last iteration. # Retain only these probabilities for departure and transfer appearences (exculde # arrivals). A31 = np.zeros((num_stops,num_ods)) for r_origin in range(num_stops): for s_dest in range(num_stops): for i_stop in range(num_stops): if i_stop != s_dest: A31[i_stop, num_stops * r_origin + s_dest] = od_flow_vector_to_stop_prob[r_origin,s_dest,i_stop] A3 = np.concatenate((A31, A32_A33_A34), axis=1) # A = np.concatenate((A1, A2, A3), axis=0) # A will change when A31 changes A = np.concatenate((A1_A2, A3), axis=0) # Transform numpy matrix to cvxopt matrix A = matrix(A, tc='d') print() print(' Quadratic programming solvers begins.') sol = solvers.qp(Q, p, G, h, A, b) print(' Solvers finished once.') print(' status:') print(sol['status']) # 'sol' is dictionary # Key: 'status', 'x', 'primal objective' if sol['status'] == 'optimal': od_flow_vector = sol['x'][0 : num_ods] print(' The optimal od_flow_vector is: (length: ' + str(len(od_flow_vector)) + ')') print(od_flow_vector) else: print(' Error: no optimal solution found!') # Stop iteration converg_flag = 1 # Convert od_flow_vector to od_flow matrix first, then use latter as input. # Note: this act is aimed at uniforming the data exchanging format with other modules, # like time-dependent module. for r_origin in range(num_stops): for s_dest in range(num_stops): od_flow[r_origin,s_dest] = od_flow_vector[r_origin * num_stops + s_dest] # Save files. np.save("results/static/od_flow_iteration_" + str(iteration_count), od_flow) # Lower level print(' Lower level begins...') # Apply static assignment model. # Input static network, od flow. od_flow_vector_to_stop_prob = static_assignment_algorithm(sn, od_flow) # Convergence test if iteration_count >= 2: avg_abs_relative_change = 0 for r_origin in range(num_stops): for s_dest in range(num_stops): if (od_flow_last[r_origin,s_dest] + od_flow[r_origin,s_dest]) != 0: avg_abs_relative_change += abs(od_flow_last[r_origin,s_dest] - od_flow[r_origin,s_dest])\ / ((od_flow_last[r_origin,s_dest] + od_flow[r_origin,s_dest]) / 2) avg_abs_relative_change /= num_ods print(" (Upper level) Iteration: " + str(iteration_count) + " avg_abs_relative_change:" + str(avg_abs_relative_change)) if avg_abs_relative_change < CONVERGENCE_CRITERION: print(" Upper level CONVERGENCE_CRITERION met!") np.save("results/static/od_flow", od_flow) converg_flag = 1 od_flow_last = od_flow if iteration_count >= MAX_NUMBER_OF_ITERATIONS: print(' Warning! bi-level problem not converging at ' + str(MAX_NUMBER_OF_ITERATIONS) + 'th iteration!') sys.exit(1) iteration_count += 1 return od_flow
def find_initial_strategy(tn): """ Input the time-dependent network; output an initil strategy.""" print(" --------------------------") print(" Finding initial strategy begins ...") DISPLAY_PROGRESS = int(open_config_file('DISPLAY_PROGRESS')) TEST = int(open_config_file('test_find_initial_strategy')) num_stops = len(tn.stops) num_stops_exp = len(tn.stops_exp) num_choices = len(tn.routes) + 1 T = tn.T prefer_links_optimal = {} prefer_probs_optimal = {} temp_key_set = set() for r in range(num_stops): for l in range(num_choices): for i_t in range(num_stops_exp): t = tn.stops_exp_2[i_t][2] temp = 0 if l != (num_choices - 1): temp = t for tau in range(temp, t + 1): temp_key_set.add((r,l,tau,i_t)) prefer_links_optimal = {key: [] for key in temp_key_set} prefer_probs_optimal = {key: [] for key in temp_key_set} # Range over destination. for r in range(num_stops): dest_name = tn.stops[r] if DISPLAY_PROGRESS == 1: print(" * * *") print(" Current destination: " + dest_name + " - " + str(r)) # Make a cpoy of tn.stops_exp and tn.links_exp respectively, # since they will be modified later. links_exp_temp = deepcopy(tn.links_exp) # Add dummy node for this destination. # Sink node's index in new node list is num_stops_exp. sink_index = num_stops_exp # Add dummy links connecting r_t to r # link_count used to generate link_index. link_count = len(links_exp_temp) for t in range(T): starting_stop_index = tn.stops_exp.index(dest_name + '_' + str(t)) links_exp_temp.append([link_count,'',starting_stop_index,\ sink_index,'Dummy',0,'',float('inf'),0]) link_count += 1 # Create Graph obj a_graph = Graph(num_stops_exp + 1, links_exp_temp, tn.stops_exp_2) # Use Shortest path tree method # Find the label labels of all nodes label, sequence = a_graph.dijkstra_travel_cost(sink_index) # label could be 1) arrival_time; 2) travel_cost. # The travel_cost is recommended, since travel cost may be different from # travel time. if TEST == 1: print(" Distance of nodes in TE network to destination:") print(label) print(" sequence is:") print(sequence) # Given the destination r, find the preference sets for all node i_t for i_t in range(num_stops_exp): # Index of phisical node in tn.stop i = tn.stops_exp_2[i_t][1] # Time of this node t = tn.stops_exp_2[i_t][2] if TEST == 1: print(" Destination: " + dest_name + " - " + str(r) + " Node: " + tn.stops_exp[i_t] + " - " + str(tn.stops_exp_2[i_t])) print(" Distance:" + str(label[i_t])) # If origin = destination, left empty if tn.stops_exp_2[i_t][1] == r: continue # Here tn.links_exp is used to aviod dummy links added before. outgoing_links = [item for item in tn.links_exp if item[2] == i_t] outgoing_links = deepcopy(outgoing_links) # Add the label to sink node to the end for item in outgoing_links: item.append(label[item[3]]) # Sort according to the label to r (ascending order) outgoing_links = sorted(outgoing_links, key = lambda x: x[9]) # Delete these links that have infinite label from sink outgoing_links = [item for item in outgoing_links if item[9] != float('inf')] # If this set is not empty ... ; otherwise, this node doesn't connect to r; # Then it's preference set left empty. if outgoing_links: outgoing_links_index = [item[0] for item in outgoing_links] outgoing_routes_index = [item[1] for item in outgoing_links] outgoing_links_cost = [item[8] for item in outgoing_links] downstream_nodes = [item[3] for item in outgoing_links] # Prioritize WT route in case that its label equals some bus routes. if (num_choices - 1) in outgoing_routes_index: wt_index = outgoing_routes_index.index(num_choices - 1) # Find the most preferred route that arrival == WT route; # Note that it may equlas itself. temp_index_2 = 99999 for temp_index in range(len(outgoing_routes_index)): if (outgoing_links[temp_index][9] + outgoing_links_cost[temp_index])\ == (outgoing_links[wt_index][9] + outgoing_links_cost[wt_index]): temp_index_2 = temp_index break # If it's not itself, then switch order. if temp_index_2 != wt_index: temp = deepcopy(outgoing_links[temp_index_2]) outgoing_links[temp_index_2] = deepcopy(outgoing_links[wt_index]) outgoing_links[wt_index] = deepcopy(temp) # Update new indices. outgoing_links_index = [item[0] for item in outgoing_links] outgoing_routes_index = [item[1] for item in outgoing_links] downstream_nodes = [item[3] for item in outgoing_links] if TEST == 1: print(" outgoing_links:") print(outgoing_links) # Incoming routes l need to be find in order to construct prefer sets. # Here tn.links_exp is used to aviod dummy links added before. incoming_links = [item for item in tn.links_exp if item[2] == i_t] incoming_links = deepcopy(incoming_links) # Whether or not there is a WT link leading to node i_t, # set the WT arrival has preferece set ... # since there are departuring demand and they will come from # "WT route" in this algorithm. if incoming_links: incoming_routes_index = [item[1] for item in incoming_links] if TEST == 1: print(" incoming_routes_index:") print(incoming_routes_index) if (num_choices - 1) not in incoming_routes_index: # Note: "WT route" has index (num_choices - 1). incoming_routes_index.append(num_choices - 1) for l in incoming_routes_index: for temp_index in range(len(downstream_nodes)): if l != (num_choices - 1): prefer_links_optimal[r,l,t,i_t].append(outgoing_links_index[temp_index]) prefer_probs_optimal[r,l,t,i_t].append(0.0) else: for tau in range(t + 1): prefer_links_optimal[r,l,tau,i_t].append(outgoing_links_index[temp_index]) prefer_probs_optimal[r,l,tau,i_t].append(0.0) else: l = num_choices - 1 # In this case, you only have one incoming route - WT. for temp_index in range(len(downstream_nodes)): for tau in range(t + 1): prefer_links_optimal[r,l,tau,i_t].append(outgoing_links_index[temp_index]) prefer_probs_optimal[r,l,tau,i_t].append(0.0) if TEST == 1: print(" The initial preference set:") for l in range(num_choices): for tau in range(t + 1): if l == (num_choices - 1) or (l != (num_choices - 1) and tau == t): print(" route(l): " + str(l) + " tau: " + str(tau) + " prefer_links_optimal:") print(prefer_links_optimal[r,l,tau,i_t]) print(" route(l): " + str(l) + " tau: " + str(tau) + " prefer_probs_optimal:") print(prefer_probs_optimal[r,l,tau,i_t]) #print(prefer_routes_optimal[1,2,540]) print(" A initial strategy has been found!") return prefer_links_optimal, prefer_probs_optimal
import json import csv import math from open_config_file import open_config_file from open_data_file_with_header import open_data_file_with_header num_routes = 4 T = int(open_config_file('HORIZON')) temp = open_data_file_with_header("data/routes.csv") routes = [item[0] for item in temp] schedules = {} # The starting time of each route. starting_time = [0, 0, 0, 0, 0, 0, 0, 0] # Unit: min. frequencies = [15, 15, 15, 15, 15, 15, 15, 15] for l in range(num_routes): filename_stops = "data/R" + str(l + 1) + "_0.csv" filename_tt = "data/R" + str(l + 1) + "_tt.csv" stops = [] tt = [] with open(filename_stops) as csvfile: readCSV = csv.reader(csvfile, delimiter=",") for row in readCSV: stops.append(row[0])
def static_assignment_algorithm(sn, od_flow): # Inputs # sn: statict metwork obj; # od_flow[r,s]. print( ' ------------------------------------------------------------------------------' ) print(" Static assignment algorithm begins ...") # Parameters TEST_STATIC_ASSIGN = int( open_config_file('test_static_assignment_algorithm')) MAX_NUMBER_OF_ITERATIONS = int( open_config_file('MAX_NUMBER_OF_ITERATIONS_FOR_ASSIGNMENT_MODEL')) CONVERGENCE_CRITERION = float( open_config_file('CONVERGENCE_CRITERION_FOR_ASSIGNMENT_MODEL')) TRANSIT_TYPE = open_config_file('TRANSIT_TYPE') LARGE_CONST = open_config_file('LARGE_CONST') # WAITING_TIME_COEFF is used to determine the waiting time given the frequency. WAITING_TIME_COEFF = float(open_config_file('WAITING_TIME_COEFF')) num_stops = len(sn.stops) num_stops_exp = len(sn.stops_exp) num_ods = num_stops**2 num_links_directional = len(sn.links_directional) num_links_exp = len(sn.links_exp) num_strategies = int( open_config_file('MAX_NUMBER_OF_STRATEGIES_STATIC_MODEL')) print() print(" num_stops: " + str(num_stops)) print(" num_links_exp: " + str(num_links_exp)) print(" num_strategies: " + str(num_strategies)) print() # Used for finding link index later. links_id_list = [item[0] for item in sn.links_exp] # Initialize strategy flow. strategy_flow = np.zeros((num_stops, num_stops, num_strategies)) for q in range(num_stops): for r in range(num_stops): strategy_flow[q, r, 0] = od_flow[q, r] # [q,r,s,a] strategy_flow_to_link_exp = np.zeros( (num_stops, num_stops, num_strategies, num_links_exp)) # [q,r,s,i] strategy_flow_to_stop_prob = np.zeros( (num_stops, num_stops, num_strategies, num_stops)) # Frank-Wolfe method iterations # Goal: for fixed od_flow, find the UE flow assignment. iteration_count = 0 converg_flag = 0 while converg_flag == 0: print() print(' Now is the ' + str(iteration_count) + '-th iterations...') print(" Total flow: " + str(strategy_flow.sum())) # Initialized for each iteration. od_flow_to_stop_exp_prob = np.zeros( (num_stops, num_stops, num_stops_exp)) od_flow_to_stop_prob = np.zeros((num_stops, num_stops, num_stops)) od_flow_to_link_exp = np.zeros((num_stops, num_stops, num_links_exp)) od_flow_to_link_directional = np.zeros( (num_stops, num_stops, num_links_directional)) link_flow = np.zeros(num_links_directional) # Update TC depeding on flow from last iteration. if iteration_count >= 1: # Note: it's sn.links_exp cost being modfied, not sn.links_directional. for a in range(num_links_exp): if sn.links_exp[a][4] == TRANSIT_TYPE: sn.links_exp[a][8] = congestion_penalty_coeff(link_flow[a],sn.links_exp[a][7], TRANSIT_TYPE)\ * sn.links_exp[a][5] #cost = congestion penalty coefficient * TT # Spiess' algorithm # r: origin index (numeric) # s: destination index (numeric) # a: link index (numeric) # u_label: node labels # S_set: set of links not examined # A_set: set of links in optimal strategy # Assign flow from all origins (excluding current destination) to # a destination - s - at a time. # Note: only stops in sn.stops could be destinations and origins. for r_dest in range(num_stops): dest_name = sn.stops[r_dest] print(' (Step 1 - backward traverse) Current destination: ' + dest_name + " - " + str(r_dest)) # Step 1 - reverse traverse to obtain optimal strategy print() print( " Iteration " + str(iteration_count) + " Step 1 - backward traverse to obtain optimal strategy begins ..." ) # Initialization # "u"" stores the distance labels u_label = LARGE_CONST * np.ones(num_stops_exp) u_label[r_dest] = 0 # "f" stores the combined frequency of nodes f_freq = np.zeros(num_stops_exp) # "S_set" stores links not examined; # Make a copy from sn.link_exp. S_set = deepcopy(sn.links_exp) # "A_set" stores the optimal strategy. A_set = [] # While S not empty, do while S_set: # Initialize min_cost_link_index = 0 min_cost = LARGE_CONST # Find the least (cij + uj) link for a in range(len(S_set)): # Get the distance label of the ending stop. end_stop_index = sn.stops_exp.index(S_set[a][3]) end_stop_label = u_label[end_stop_index] if S_set[a][8] + end_stop_label < min_cost: # Use cost of link_exp. min_cost = S_set[a][8] + end_stop_label min_cost_link_index = a if TEST_STATIC_ASSIGN == 1: print() print(' min cost link:') print(S_set[min_cost_link_index]) end_stop_index = sn.stops_exp.index( S_set[min_cost_link_index][3]) end_stop_label = u_label[end_stop_index] if TEST_STATIC_ASSIGN == 1: print(' link_travel_cost: ' + str(S_set[min_cost_link_index][8]) + ' end_stop_distance_label is:' + str(end_stop_label)) # Update label u and combined frequency if needed. # "start_stop" means the upstream stop of the link. start_stop = S_set[min_cost_link_index][2] start_stop_index = sn.stops_exp.index(start_stop) # Flag for updating type: # 0: no update; # 1: first time update; # 2: update, not for the first time update_flag = [] if u_label[start_stop_index] <= min_cost: update_flag = 0 if TEST_STATIC_ASSIGN == 1: print(' no update.') elif u_label[start_stop_index] > min_cost: if u_label[start_stop_index] >= LARGE_CONST: update_flag = 1 # If this link has inf freq. if S_set[min_cost_link_index][6] == LARGE_CONST: u_label[start_stop_index] = min_cost else: # Note that the time unit is min; # Note the WAITING_TIME_COEFF. u_label[start_stop_index] = 60 / S_set[ min_cost_link_index][6] + min_cost f_freq[start_stop_index] = S_set[min_cost_link_index][ 6] else: update_flag = 2 u_label[start_stop_index] = ( (f_freq[start_stop_index] * u_label[start_stop_index] + S_set[min_cost_link_index][6] * min_cost) / (f_freq[start_stop_index] + S_set[min_cost_link_index][6])) f_freq[start_stop_index] += S_set[min_cost_link_index][ 6] if TEST_STATIC_ASSIGN == 1: print(' Updated stop is: ' + sn.stops_exp[start_stop_index] + ' - ' + str(start_stop_index)) print(' Distance label:' + str(u_label[start_stop_index]) + ' combined frequency: ' + str(f_freq[start_stop_index])) # Add this link to attractive set A_set.append(S_set[min_cost_link_index]) if TEST_STATIC_ASSIGN == 1: print( ' This link is added to optimal strategy set.') # Remove examined link from S del S_set[min_cost_link_index] A_set_links_id = [item[0] for item in A_set] if TEST_STATIC_ASSIGN == 1: print() print(' All links being examined.') print( ' The node distance labels (u) and frequencies (f) are:' ) for temp_index in range(num_stops_exp): print(" Node name: " + sn.stops_exp[temp_index]) print(" Distance label: " + str(u_label[temp_index])) print(" Combined frequencies (f): " + str(f_freq[temp_index])) print() print(' The optimal strategy (A) for destination ' + sn.stops[r_dest] + ' is:') print(A_set) # Step 2: forward traverse to assigne flow to optimal strategy # Note: dest s is still fixed. print() print( " Iteration " + str(iteration_count) + " Step 2 - forward traverse to assigne flow to optimal strategy begins." ) print(' (Step 2: forward traverse) Current destination: ' + sn.stops[r_dest]) # First obtain {cij + uj} for all links # Used for sorting; # Now 'links_sorted' is unsorted yet. links_sorted = deepcopy(sn.links_exp) for a in range(num_links_exp): end_stop_index = sn.stops_exp.index(links_sorted[a][3]) end_stop_label = u_label[end_stop_index] # Add a col 9; # Note: don't modify col 8, cost; # Col 8 is for cost with congestion effect links_sorted[a].append( float(links_sorted[a][8] + end_stop_label)) # Then sort links according to {cij + uj} in decreasing order links_sorted = sorted(links_sorted, key=lambda x: x[9], reverse=True) print(' links sorted according to {cij + uj}:') print(links_sorted) # Iterate over all origins so that prob for each od pair could be obtained. # Note: dest r_dest is still fixed. for q_origin in range(num_stops): # v_stop is used to store the flow that appears at each node; # v_link is used to store the flow that appears at each link; v_stop = np.zeros((num_stops_exp)) v_link = np.zeros((num_links_exp)) # Assign od flow from q_origin to r_dest # Unit flow is first assigned in order to obtain assign probability. v_stop[q_origin] = 1.0 for link in links_sorted: start_stop = link[2] start_stop_index = sn.stops_exp.index(start_stop) end_stop = link[3] end_stop_index = sn.stops_exp.index(end_stop) link_index = links_id_list.index(link[0]) if link[0] in A_set_links_id: # Note: # 1) there is an additional colume in links_sorted, hence "-1" # 2) link index in sn.links_exp is needed since od_flow_to_link_directional_prob_exp is arranged # according to that sequence; # 3) this sorted seq is temporary -- for each q_origin-r_dest, the seq # may be different; v_link[link_index] += (v_stop[start_stop_index] * link[6] / f_freq[start_stop_index]) v_stop[end_stop_index] += v_link[link_index] else: v_link[link_index] = 0 od_flow_to_stop_exp_prob[q_origin, r_dest, :] = v_stop # Extract the first num_stops elmts # Multiply the r-s flow v_link = od_flow[q_origin, r_dest] * v_link od_flow_to_link_exp[q_origin, r_dest, :] = v_link print() print(' Current destination: ' + dest_name + ' - ' + str(r_dest) + ' current origin: ' + sn.stops[q_origin] + ' - ' + str(q_origin)) if TEST_STATIC_ASSIGN == 1: for temp_index in range(num_stops): print(" Assignment probability of flow " + " to stops: " + sn.stops[temp_index] + " v_stop:" + str(v_stop[temp_index])) print(" Assignment flow of flow from " + dest_name + " to links (v_link):") print(v_link) print() print(' All origins and destinations visited once.') # Extract non "_exp" info. for q_origin in range(num_stops): for r_dest in range(num_stops): od_flow_to_link_directional[q_origin, r_dest, :] = od_flow_to_link_exp[ r, r_dest, 0:num_links_directional] # Note: if od_flow_to_stop_prob[r,s,:] = od_flow_to_stop_exp_prob[r,s,0 : num_stops] # is used, then only transfer flow will be recorded; # Only stops from num_stops to num_stops_exp will be counted; namely nodes like N2_R2_1; for index in range(num_stops, num_stops_exp): temp = sn.stops_exp[index].split('_')[0] i = sn.stops.index(temp) od_flow_to_stop_prob[q_origin, r_dest, i] += od_flow_to_stop_exp_prob[ q_origin, r_dest, index] if TEST_STATIC_ASSIGN == 1 and od_flow_to_stop_exp_prob[ q_origin, r_dest, index] > 0.000001: print() print(" Step 1) od_flow_to_stop_prob" + str([q_origin, r_dest, i]) + " updated to: " + str(od_flow_to_stop_prob[q_origin, r_dest, i])) # Delete repetition counts. # Note that flow that transfer at node N1 from R1 to R2 will be counted # at N1_R1_0, N1, and N1_R2_0; for index in range(num_stops): if index != q_origin and index != r_dest: od_flow_to_stop_prob[ q_origin, r_dest, index] -= od_flow_to_stop_exp_prob[q_origin, r_dest, index] if TEST_STATIC_ASSIGN == 1 and od_flow_to_stop_exp_prob[ q_origin, r_dest, index] > 0.000001: print() print(" Step 2) od_flow_to_stop_prob" + str([q_origin, r_dest, index]) + " updated to: " + str(od_flow_to_stop_prob[q_origin, r_dest, index])) # Save results. np.save( 'results/static/od_flow_to_stop_prob_iteration_' + str(iteration_count), od_flow_to_stop_prob) np.save( 'results/static/od_flow_to_link_directional_iteration_' + str(iteration_count), od_flow_to_link_directional) if iteration_count >= MAX_NUMBER_OF_ITERATIONS: print(' Warning! Diagnolization method not converging at ' + str(MAX_NUMBER_OF_ITERATIONS) + 'th iteration!') converg_flag = 1 # Use MSA to update the strategy flow. # Note that probabilities don't need MSA; flow need. for q_origin in range(num_stops): for r_dest in range(num_stops): for i in range(num_stops): strategy_flow_to_stop_prob[ q_origin, r_dest, iteration_count, i] = od_flow_to_stop_prob[q_origin, r_dest, i] # Direction direction strategy flow. Y_strategy = np.zeros((num_stops, num_stops, num_strategies)) for q in range(num_stops): for r in range(num_stops): Y_strategy[q, r, iteration_count] = od_flow[q, r] # Direction direction link flow. Y_link_exp = np.zeros( (num_stops, num_stops, num_strategies, num_links_exp)) for q_origin in range(num_stops): for r_dest in range(num_stops): for a in range(num_links_exp): Y_link_exp[q_origin, r_dest, iteration_count, a] = od_flow_to_link_exp[q_origin, r_dest, a] if iteration_count == 0: strategy_flow_to_link_exp = deepcopy(Y_link_exp) else: strategy_flow = 1 / (iteration_count + 1) * ( iteration_count * strategy_flow + Y_strategy) strategy_flow_to_link_exp = 1 / (iteration_count + 1) * ( iteration_count * strategy_flow_to_link_exp + Y_link_exp) # Calculate link_flow. for a in range(num_links_directional): link_flow[a] = strategy_flow_to_link_exp[:, :, :, a].sum() # Print results. if TEST_STATIC_ASSIGN == 1: print() print(" link_flow:") for temp_index in range(num_links_directional): if link_flow[temp_index] > 0.0001: print(" Link: " + str(sn.links_directional[temp_index])) print(" Link flow: " + str(link_flow[temp_index])) # Compute return for q_origin in range(num_stops): for r_dest in range(num_stops): if od_flow[r, r_dest] > 0.0001: for i_stop in range(num_stops): temp = 0 for s_strategy in range(num_strategies): temp += strategy_flow[ q_origin, r_dest, s_strategy] * strategy_flow_to_stop_prob[ q_origin, r_dest, s_strategy, i_stop] od_flow_to_stop_prob[q_origin, r_dest, i_stop] = temp / od_flow[q_origin, r_dest] # Convergence test if iteration_count >= 2: avg_abs_relative_change = 0 for a in range(num_links_directional): if (link_flow[a] + link_flow_last[a]) != 0: avg_abs_relative_change += abs( link_flow[a] - link_flow_last[a]) / ( (link_flow[a] + link_flow_last[a]) / 2) avg_abs_relative_change /= num_links_directional print(" (Lower levle) iteration: " + str(iteration_count) + " avg_abs_relative_change: " + str(avg_abs_relative_change)) if avg_abs_relative_change < CONVERGENCE_CRITERION: converg_flag = 1 print(" Lower level CONVERGENCE_CRITERION met!") else: print( " CONVERGENCE_CRITERION not met; next iteration begins..." ) link_flow_last = deepcopy(link_flow) iteration_count += 1 return od_flow_to_stop_prob
import numpy as np from TimeExpandedNetwork import TimeExpandedNetwork from open_config_file import open_config_file from random_choice import random_choice tn = TimeExpandedNetwork() DEMAND_LEVEL = open_config_file('DEMAND_LEVEL') ANALYSIS_START = open_config_file('ANALYSIS_START') ANALYSIS_PERIOD = open_config_file('ANALYSIS_PERIOD') T = tn.T N = len(tn.stops) od_flow = np.zeros((N,N,T)) if DEMAND_LEVEL == 'high': for q in range(N): for r in range(N): if q != r: for h in range(ANALYSIS_START, ANALYSIS_START + ANALYSIS_PERIOD): od_flow[q,r,h] = random_choice("high") if DEMAND_LEVEL == 'mid': for q in range(N): for r in range(N): if q != r: for h in range(ANALYSIS_START, ANALYSIS_START + ANALYSIS_PERIOD): od_flow[q,r,h] = random_choice("mid")
def dynamic_schedule_based_ue_model(tn): """ Input TimeExpandedNetwork obj; output the time-dependent equilibrium flow.""" print(' ---------------------------------------------------') print(" Time-dependent model begins ...") # Parameters TEST_QUADRATIC_PROG = int(open_config_file('test_quadratic_programming')) QUADRATIC_PROG_SOLVING_PKG = open_config_file('QUADRATIC_PROG_SOLVING_PKG') INTEGER_PROG = float(open_config_file('INTEGER_PROG')) # Number of stops N = len(tn.stops) # Horizon T = tn.T MAX_NUMBER_OF_ITERATIONS = int( open_config_file('MAX_NUMBER_OF_ITERATIONS_FOR_BILEVEL_MODEL')) CONVERGENCE_CRITERION = float( open_config_file('CONVERGENCE_CRITERION_FOR_BILEVEL_MODEL')) # Number of bus lines. num_routes = len(tn.routes) # The most number of choices user could have at a node, which equals # the number of routes, adding a waiting link. num_choices = num_routes + 1 # Periods of measurements (Unit: min) C = int(open_config_file('MEASUREMENT_PERIOD')) # Times of measurements I = int(T / C) sys.setrecursionlimit(5000000) global m print() print(" Horion (T): " + str(T)) print(" Measurements period C: " + str(C)) print(" Times of measurements I: " + str(I)) print(" Optimization package: " + QUADRATIC_PROG_SOLVING_PKG) # Initialization od_flow = np.zeros((N, N, T)) # Input Data # Count data. entry_count = [] exit_count = [] wifi_count = [] passby_count = [] # Retain only data column. entry_count_file = open_data_file_with_header( 'data/entry_count_by_designated_period.csv') exit_count_file = open_data_file_with_header( 'data/exit_count_by_designated_period.csv') wifi_count_file = open_data_file_with_header( 'data/wifi_count_by_designated_period.csv') # Data formats: # (col) 1 2 3 # measurement_seq_number, stop_id, count # Retain only count data. entry_count = [float(item[2]) for item in entry_count_file] exit_count = [float(item[2]) for item in exit_count_file] wifi_count = [float(item[2]) for item in wifi_count_file] # Convert wifi count to stop count. # i) First, import ratio file. wifi_sample_ratio = open_data_file_with_header( 'data/wifi_sample_ratio.csv') # Table header: # 0 # sample_ratio wifi_sample_ratio = [float(item[0]) for item in wifi_sample_ratio] # ii) Second, transform. passby_count = [] for k_meas in range(I): for i_stop in range(N): # Note: wifi_count is list passby_count.append(wifi_count[k_meas * N + i_stop] / wifi_sample_ratio[i_stop]) # Print measurements data. if TEST_QUADRATIC_PROG == 1: print() print(' Measurements data:') print(' entry_count:') print(entry_count) print(' exit_count:') print(exit_count) print(' wifi_count:') print(wifi_count) print(' wifi_sample_ratio:') print(wifi_sample_ratio) print(' passby_count:') print(passby_count) # End of test print. # Prepare coefficients for solve quadratic programming # Non-integer prog if QUADRATIC_PROG_SOLVING_PKG == "cvxopt": # Coefficients: Q,p,A,b,G,h # Q & p Q = np.zeros((N * N * T + 3 * N * T, N * N * T + 3 * N * T)) p = np.zeros((N * N * T + 3 * N * T, 1)) # period k_meas for k_meas in range(I): # stop n for i_stop in range(N): for t1 in range(C * k_meas, C * (k_meas + 1)): for t2 in range(C * k_meas, C * (k_meas + 1)): Q[N * N * T + N * t1 + i_stop, N * N * T + N * t2 + i_stop] = 2 Q[N * N * T + N * T + N * t1 + i_stop, N * N * T + N * T + N * t2 + i_stop] = 2 Q[N * N * T + 2 * N * T + N * t1 + i_stop, N * N * T + 2 * N * T + N * t2 + i_stop] = 2 # p p[N * N * T + N * t1 + i_stop, 0] = (-2) * entry_count[N * k_meas + i_stop] p[N * N * T + N * T + N * t1 + i_stop, 0] = (-2) * exit_count[N * k_meas + i_stop] p[N * N * T + 2 * N * T + N * t1 + i_stop, 0] = (-2) * passby_count[N * k_meas + i_stop] # A # A will be fully determined in the iterations. # Initialized here. A = np.zeros((3 * N * T, N * N * T + 3 * N * T)) # b is zero as default. b = np.zeros((3 * N * T, 1)) # G # var >= 0, namely - var <= 0. G = (-1) * np.identity(N * N * T + 3 * N * T) # h is zero as default. h = np.zeros((N * N * T + 3 * N * T, 1)) # Transform numpy matrices to cvxopt matrices. Q = matrix(Q, tc='d') p = matrix(p, tc='d') G = matrix(G, tc='d') h = matrix(h, tc='d') b = matrix(b, tc='d') # Mixed integer prog. # Sparse model. elif QUADRATIC_PROG_SOLVING_PKG == "gurobi" and platform.system( ) != 'Windows': m = Model("qp") # Create variables # f_i_j_h for q_origin in range(N): for r_dest in range(N): for h_depart in range(T): if INTEGER_PROG == 1: exec( "f_%d_%d_%d = m.addVar(vtype=GRB.INTEGER, lb=0, name='f_%d_%d_%d')" % (q_origin, r_dest, h_depart, q_origin, r_dest, h_depart), globals()) elif INTEGER_PROG == 0: exec( "f_%d_%d_%d = m.addVar(vtype=GRB.CONTINUOUS, lb=0, name='f_%d_%d_%d')" % (q_origin, r_dest, h_depart, q_origin, r_dest, h_depart), globals()) # o_q_h for q_origin in range(N): for h_depart in range(T): exec( "o_%d_%d = m.addVar(vtype=GRB.CONTINUOUS, lb=0, name='o_%d_%d')" % (q_origin, h_depart, q_origin, h_depart), globals()) # d_r_t for r_dest in range(N): for t in range(T): exec( "d_%d_%d = m.addVar(vtype=GRB.CONTINUOUS, lb=0, name='d_%d_%d')" % (r_dest, t, r_dest, t), globals()) # x_i_t for i_stop in range(N): for t in range(T): exec( "x_%d_%d = m.addVar(vtype=GRB.CONTINUOUS, lb=0, name='x_%d_%d')" % (i_stop, t, i_stop, t), globals()) # Set objective obj_str = 'obj = ' for k_meas in range(I): # o_q_h for q_origin in range(N): temp_str = '(' for h_depart in range(C * k_meas, C * (k_meas + 1)): temp_str += 'o_' + str(q_origin) + '_' + str(h_depart) if h_depart != C * (k_meas + 1) - 1: temp_str += '+' temp_str += ' - ' + str(entry_count[N * k_meas + q_origin]) temp_str += ')' obj_str += temp_str + '*' + temp_str obj_str += ' + ' # d_r_t for r_dest in range(N): temp_str = '(' for t in range(C * k_meas, C * (k_meas + 1)): temp_str += 'd_' + str(r_dest) + '_' + str(t) if t != C * (k_meas + 1) - 1: temp_str += '+' temp_str += ' - ' + str(exit_count[N * k_meas + r_dest]) temp_str += ')' obj_str += temp_str + '*' + temp_str obj_str += ' + ' # x_i_t for i_stop in range(N): temp_str = '(' for t in range(C * k_meas, C * (k_meas + 1)): temp_str += 'x_' + str(i_stop) + '_' + str(t) if t != C * (k_meas + 1) - 1: temp_str += '+' temp_str += ' - ' + str(passby_count[N * k_meas + i_stop]) temp_str += ')' obj_str += temp_str + '*' + temp_str if not (i_stop == (N - 1) and k_meas == (I - 1)): obj_str += ' + ' if TEST_QUADRATIC_PROG == 1: print() print(" objective is:") print(obj_str) # End of test print. exec(obj_str, globals()) m.setObjective(obj, GRB.MINIMIZE) # Add constraints (part). count_constraint = 0 # o_q_h for q_origin in range(N): for h_depart in range(T): const_str = '' temp_count = 0 for r_dest in range(N): if r_dest != q_origin: if temp_count != 0: const_str += ' + ' const_str += 'f_' + str(q_origin) + '_' + str( r_dest) + '_' + str(h_depart) temp_count += 1 if temp_count > 0: const_str += ' == ' const_str += 'o_' + str(q_origin) + '_' + str(h_depart) if TEST_QUADRATIC_PROG == 1: print() print(" A entry count constraint is added: ") print(const_str) # End of test print. m.addConstr(eval(const_str), 'c' + str(count_constraint)) count_constraint += 1 # d_r_t # TBD # x_r_t # TBD elif QUADRATIC_PROG_SOLVING_PKG == "gurobi" and platform.system( ) == 'Windows': pass elif QUADRATIC_PROG_SOLVING_PKG != "cvxopt" and QUADRATIC_PROG_SOLVING_PKG != "gurobi": print() print(" Error: Unkown method!") sys.exit(1) print(' --------------------------') print(' Bi-level programming iterations begins ... ') # Bi-level programming iterations # Initialization iteration_count = 0 converg_flag = 0 # While convergence or maximum, iteration not reached, continue to loop. while converg_flag == 0: # Upper level print() print(" Bi-level iteration: " + str(iteration_count)) print(' Upper level begins ...') print(" Find initial od_flow_to_stop_prob...") # Initialize the cost of links for index in range(len(tn.links_exp)): tn.links_exp[index][8] = tn.links_exp[index][5] # Initialize od_flow_to_stop_prob. # Users will follow the path determined by the initial preference set. # No capacity constraints etc. considered. if iteration_count == 0: prefer_links_optimal, prefer_probs_optimal = find_initial_strategy( tn) od_flow_to_stop_prob = np.zeros((N, N, T, N, T)) for q_origin in range(N): for r_dest in range(N): if q_origin != r_dest: for h_depart in range(T): # Initialize departure node in TE network. # Notations inherated from dynamic_schedule_based_ue_assignment_algorithm. i = q_origin t = h_depart i_t = tn.stops_exp.index(tn.stops[q_origin] + '_' + str(h_depart)) # coming from route l = num_choices - 1 tau = h_depart arrive_dest_flag = 0 while arrive_dest_flag == 0: if TEST_QUADRATIC_PROG == 1: print() print(" Current [q,r,h]: " + str([q_origin, r_dest, h_depart]) + " current node: " + str(tn.stops_exp[i_t]) + " - " + str(i_t)) print(" prefer_links_optimal:") print(prefer_links_optimal[r_dest, l, tau, i_t]) # End of test print. # Update od_flow_to_stop_prob for current node. if i == q_origin and t == h_depart: od_flow_to_stop_prob[q_origin, r_dest, h_depart, i, t] = 1.0 if TEST_QUADRATIC_PROG == 1: print() print( " Entry count od_flow_to_stop_prob" + str([ q_origin, r_dest, h_depart, i, t ]) + " updated to 1.") # End of test print. if i == r_dest: od_flow_to_stop_prob[q_origin, r_dest, h_depart, i, t] = 1.0 if TEST_QUADRATIC_PROG == 1: print() print( " Exit count od_flow_to_stop_prob" + str([ q_origin, r_dest, h_depart, i, t ]) + " updated to 1.") # End of test print. if i != q_origin and i != r_dest and l != ( num_choices - 1): od_flow_to_stop_prob[q_origin, r_dest, h_depart, i, t] = 1.0 if TEST_QUADRATIC_PROG == 1: print() print( " Passby count od_flow_to_stop_prob" + str([ q_origin, r_dest, h_depart, i, t ]) + " updated to 1.") # End of test print. # Update arrive_dest_flag if needed. if i == r_dest: arrive_dest_flag == 1 if TEST_QUADRATIC_PROG == 1: print() print(" Arrive at destination.") # End of test print. break # Find next node. # If preference set not empty, which means it's able to get to the destination in T; if prefer_links_optimal[r_dest, l, tau, i_t]: link_next = prefer_links_optimal[r_dest, l, tau, i_t][0] l_next = tn.links_exp[link_next][1] i_t_next = tn.links_exp[link_next][3] i_next = tn.stops_exp_2[i_t_next][1] t_next = tn.stops_exp_2[i_t_next][2] if l_next == (num_choices - 1): tau_next = tau else: # Use TT to update tau. tau_next = t_next else: if TEST_QUADRATIC_PROG == 1: print() print( " This node cannot reach destination within horizon." ) # End of test print. break # Update node. i_t = i_t_next i = i_next t = t_next l = l_next tau = tau_next if QUADRATIC_PROG_SOLVING_PKG == "cvxopt": # A # Adopt od_flow_to_stop_prob matrix from assignment of last iteration to obtain A. # For enter measurement at node r_h_depart for h_depart in range(T): for q_origin in range(N): # flow var coeff for r_dest in range(N): A[N * h_depart + q_origin, N * N * h_depart + N * q_origin + r_dest] = 1 # Measurement var (O) coeff A[N * h_depart + q_origin, N * N * T + N * h_depart + q_origin] = -1 # For exit measurement at node s_t for t_exit in range(T): for r_dest in range(N): # flow var coeff for q_origin in range(N): for h_depart in range(t_exit): if q_origin != r_dest: A[N * T + N * t_exit + r_dest, N * N * h_depart + N * q_origin + r_dest] = od_flow_to_stop_prob[q_origin, r_dest, h_depart, r_dest, t_exit] # Measurement var (D) coeff # Remember to use t! A[N * T + N * t_exit + r_dest, N * N * T + N * T + N * t_exit + r_dest] = -1 # For passby measurement at node n_t for i_stop in range(N): for t_passby in range(T): # Q # Note that enter flows could also be detedted by wifi, hence here # h_depart range in 0 ~ t. for h_depart in range(t_passby): for q_origin in range(N): for r_dest in range(N): if i_stop != q_origin and i_stop != r_dest: A[2 * N * T + N * t_passby + i_stop, N * N * h_depart + N * q_origin + r_dest] = od_flow_to_stop_prob[q_origin, r_dest, h_depart, i_stop, t_passby] # Measuremnt var (X) coeff # Remember to use t! A[2 * N * T + N * t_passby + i_stop, N * N * T + 2 * N * T + N * t_passby + i_stop] = -1 print() print(' Quadratic programming solver begins ...') # Transform numpy matrix to cvxopt matrix A = matrix(A, tc='d') sol = solvers.qp(Q, p, G, h, A, b) print() print(' Solver finished once!') print(' Slover status:') print(sol['status']) # 'sol' is dictionary # Key: 'status', 'x', 'primal objective' if sol['status'] == 'optimal': print() optimal_objective = sol['primal objective'] # Add constants neglected in optimization. for k_meas in range(I): for i_stop in range(N): optimal_objective += entry_count[N * k_meas + i_stop]**2 optimal_objective += exit_count[N * k_meas + i_stop]**2 optimal_objective += passby_count[N * k_meas + i_stop]**2 print("Optimal objective " + str(optimal_objective)) for q_origin in range(N): for r_dest in range(N): for h_depart in range(T): od_flow[q_origin, r_dest, h_depart] = sol['x'][N * N * h_depart + N * q_origin + r_dest] else: print() print(' Error: no optimal solution found!') # Stop iteration sys.eixt(1) # Sparse matrix elif QUADRATIC_PROG_SOLVING_PKG == "gurobi": # If the platform is Win, objective and constraints should be added. if platform.system() == 'Windows': m = Model("qp") # Create variables # f_i_j_h for q_origin in range(N): for r_dest in range(N): for h_depart in range(T): if INTEGER_PROG == 1: exec( "f_%d_%d_%d = m.addVar(vtype=GRB.INTEGER, lb=0, name='f_%d_%d_%d')" % (q_origin, r_dest, h_depart, q_origin, r_dest, h_depart), globals()) elif INTEGER_PROG == 0: exec( "f_%d_%d_%d = m.addVar(vtype=GRB.CONTINUOUS, lb=0, name='f_%d_%d_%d')" % (q_origin, r_dest, h_depart, q_origin, r_dest, h_depart), globals()) # o_q_h for q_origin in range(N): for h_depart in range(T): exec( "o_%d_%d = m.addVar(vtype=GRB.CONTINUOUS, lb=0, name='o_%d_%d')" % (q_origin, h_depart, q_origin, h_depart), globals()) # d_r_t for r_dest in range(N): for t in range(T): exec( "d_%d_%d = m.addVar(vtype=GRB.CONTINUOUS, lb=0, name='d_%d_%d')" % (r_dest, t, r_dest, t), globals()) # x_i_t for i_stop in range(N): for t in range(T): exec( "x_%d_%d = m.addVar(vtype=GRB.CONTINUOUS, lb=0, name='x_%d_%d')" % (i_stop, t, i_stop, t), globals()) # Set objective obj_str = 'obj = ' for k_meas in range(I): # o_q_h for q_origin in range(N): temp_str = '(' for h_depart in range(C * k_meas, C * (k_meas + 1)): temp_str += 'o_' + str(q_origin) + '_' + str( h_depart) if h_depart != C * (k_meas + 1) - 1: temp_str += '+' temp_str += ' - ' + str( entry_count[N * k_meas + q_origin]) temp_str += ')' obj_str += temp_str + '*' + temp_str obj_str += ' + ' # d_r_t for r_dest in range(N): temp_str = '(' for t in range(C * k_meas, C * (k_meas + 1)): temp_str += 'd_' + str(r_dest) + '_' + str(t) if t != C * (k_meas + 1) - 1: temp_str += '+' temp_str += ' - ' + str( exit_count[N * k_meas + r_dest]) temp_str += ')' obj_str += temp_str + '*' + temp_str obj_str += ' + ' # x_i_t for i_stop in range(N): temp_str = '(' for t in range(C * k_meas, C * (k_meas + 1)): temp_str += 'x_' + str(i_stop) + '_' + str(t) if t != C * (k_meas + 1) - 1: temp_str += '+' temp_str += ' - ' + str( passby_count[N * k_meas + i_stop]) temp_str += ')' obj_str += temp_str + '*' + temp_str if not (i_stop == (N - 1) and k_meas == (I - 1)): obj_str += ' + ' if TEST_QUADRATIC_PROG == 1: print() print(" objective is:") print(obj_str) # End of test print. exec(obj_str, globals()) m.setObjective(obj, GRB.MINIMIZE) # Add constraints (part). count_constraint = 0 # o_q_h for q_origin in range(N): for h_depart in range(T): const_str = '' temp_count = 0 for r_dest in range(N): if r_dest != q_origin: if temp_count != 0: const_str += ' + ' const_str += 'f_' + str(q_origin) + '_' + str( r_dest) + '_' + str(h_depart) temp_count += 1 if temp_count > 0: const_str += ' == ' const_str += 'o_' + str(q_origin) + '_' + str( h_depart) if TEST_QUADRATIC_PROG == 1: print() print( " A entry count constraint is added: ") print(const_str) # End of test print. m.addConstr(eval(const_str), 'c' + str(count_constraint)) count_constraint += 1 # If the sys is not Win, delete dated constraints. if platform.system() != 'Windows' and iteration_count != 0: m.remove(m.getConstrs()[N * T:3 * N * T]) # Add other constraints in the following. count_constraint = N * T # d_r_t for r_dest in range(N): for t in range(1, T): const_str = '' temp_count = 0 for q_origin in range(N): for h_depart in range(T): if q_origin != r_dest and h_depart < t: if od_flow_to_stop_prob[q_origin, r_dest, h_depart, r_dest, t] > 0.0001: if temp_count != 0: const_str += ' + ' const_str += str( od_flow_to_stop_prob[q_origin, r_dest, h_depart, r_dest, t] ) + ' * f_' + str(q_origin) + '_' + str( r_dest) + '_' + str(h_depart) temp_count += 1 if temp_count > 0: const_str += ' == ' const_str += 'd_' + str(r_dest) + '_' + str(t) if TEST_QUADRATIC_PROG == 1: print() print(" A exit count constraint is added: ") print(const_str) # End of test print. m.addConstr(eval(const_str), 'c' + str(count_constraint)) count_constraint += 1 # x_i_t for i_stop in range(N): for t in range(T): const_str = '' temp_count = 0 for q_origin in range(N): for r_dest in range(N): for h_depart in range(T): if i_stop != q_origin and i_stop != r_dest and t > h_depart and od_flow_to_stop_prob[ q_origin, r_dest, h_depart, i_stop, t] > 0.0001: if temp_count != 0: const_str += ' + ' const_str += str( od_flow_to_stop_prob[q_origin, r_dest, h_depart, i_stop, t] ) + ' * f_' + str(q_origin) + '_' + str( r_dest) + '_' + str(h_depart) temp_count += 1 if temp_count > 0: const_str += ' == ' const_str += 'x_' + str(i_stop) + '_' + str(t) if TEST_QUADRATIC_PROG == 1: print() print(" A passby count constraint is added: ") print(const_str) # End of test print. m.addConstr(eval(const_str), 'c' + str(count_constraint)) count_constraint += 1 # Optimize model m.optimize() print(' Obj: %g' % m.objVal) if iteration_count == 0: with open("results/dynamic/obj_upper_level.csv", "w") as f: f.write(str(m.objVal)) else: with open("results/dynamic/obj_upper_level.csv", "a") as f: f.write('\n') f.write(str(m.objVal)) # Obtain results for v in m.getVars(): temp_name = v.varName temp_name = temp_name.split('_') if temp_name[0] == 'f': od_flow[int(temp_name[1]), int(temp_name[2]), int(temp_name[3])] = v.x # Save results np.save( 'results/dynamic/od_flow_upper_level_iteration_' + str(iteration_count), od_flow) print() print(' The optimal od_flow obtained!') # Lower level - Solving dynamic schedule based UE assignment problem. print(' Lower level begins ...') # If this is not a test, then update od_flow_to_stop_prob. if (TEST_QUADRATIC_PROG != 1): od_flow_to_stop_prob, link_combined_flow = dynamic_schedule_based_ue_assignment_algorithm( tn, od_flow, od_flow_to_stop_prob) #np.save('results/dynamic/od_flow_to_stop_prob_upper_level_iteration_' + str(iteration_count), od_flow_to_stop_prob) np.save( 'results/dynamic/link_combined_flow_upper_level_iteration_' + str(iteration_count), link_combined_flow) else: print() print( " Testing quadratic prog; od_flow_to_stop_prob is not updated." ) # Convergence test. if iteration_count >= 1: avg_mse_od_flow = 0 for r in range(N): for s in range(N): for h_depart in range(T): avg_mse_od_flow += (od_flow_last[r, s, h_depart] - od_flow[r, s, h_depart])**2 #if abs(od_flow_last[r,s,h_depart] - od_flow[r,s,h_depart]) > 0.1: # print() # print(" od_flow_last" + str([r,s,h_depart]) + ": " + str(od_flow_last[r,s,h_depart])) # print(" od_flow" + str([r,s,h_depart]) + ": " + str(od_flow[r,s,h_depart])) avg_mse_od_flow /= N * N * T print() print(" Iteration: " + str(iteration_count) + " avg_mse_od_flow: " + str(avg_mse_od_flow)) if iteration_count == 1: with open("results/dynamic/avg_mse_od_flow_upper_level.csv", 'w') as f: f.write(str(avg_mse_od_flow)) else: with open("results/dynamic/avg_mse_od_flow_upper_level.csv", 'a') as f: f.write('\n') f.write(str(avg_mse_od_flow)) avg_mse_link_flow = 0 for link_index in range(len(link_combined_flow)): avg_mse_link_flow += (link_combined_flow_last[link_index] - link_combined_flow[link_index])**2 #if abs(link_combined_flow_last[link_index] - link_combined_flow[link_index]) > 0.1: # print() # print(" link_combined_flow_last" + str([link_index]) + ": " + str(link_combined_flow_last[link_index])) # print(" link_combined_flow" + str([link_index]) + ": " + str(link_combined_flow[link_index])) avg_mse_link_flow /= len(link_combined_flow) print() print(" Iteration: " + str(iteration_count) + " avg_mse_link_flow: " + str(avg_mse_link_flow)) if iteration_count == 1: with open("results/dynamic/avg_mse_link_flow_upper_level.csv", 'w') as f: f.write(str(avg_mse_link_flow)) else: with open("results/dynamic/avg_mse_link_flow_upper_level.csv", 'a') as f: f.write('\n') f.write(str(avg_mse_link_flow)) if avg_mse_od_flow < CONVERGENCE_CRITERION and avg_mse_link_flow < CONVERGENCE_CRITERION: print() print("Convergence reached!") converg_flag = 1 continue od_flow_last = deepcopy(od_flow) link_combined_flow_last = deepcopy(link_combined_flow) if iteration_count >= MAX_NUMBER_OF_ITERATIONS: print() print(' Warning! bi-level prog not converging at ' + str(MAX_NUMBER_OF_ITERATIONS) + 'th iteration!') sys.exit(1) iteration_count += 1 return od_flow
def __init__(self): print( ' ------------------------------------------------------------------------------' ) print(" Creating a static network object ...") # Config # Small constant SMALL_CONST = float(open_config_file('SMALL_CONST')) LARGE_CONST = open_config_file('LARGE_CONST') TRANSIT_TYPE = open_config_file('TRANSIT_TYPE') TEST_SN = open_config_file('test_StaticNetwork') # Read files from '/data', remove header, decompose elmts self.stops = open_data_file_with_header('data/stops.csv') # 0 # stop_id self.stops = [item[0] for item in self.stops] self.routes = open_data_file_with_header('data/routes.csv') # 0 # route_id # Will be made directional later. self.routes = [item[0] for item in self.routes] self.links = open_data_file_with_header('data/links.csv') # 0 1 2 3 4 5 #link_id,route_id,starting_stop,ending_stop,link_type,travel_time, # 6 7 8 #frequency,capacity,travel_cost # Note: the links are bi-directional, they have to be decomposed into two # uni-directional links later. # link type in raw file left empty. self.frequencies = open_data_file_with_header('data/frequencies.csv') # 1 # headway_secs # Note: frequrncies' corrusponding routes must be the same with self.routes file. self.frequencies = [item[0] for item in self.frequencies] self.routes_directional = [] # Decompose routes into directional routes. for item in self.routes: # Add directions # Elmts being string self.routes_directional.append(item + '_0') self.routes_directional.append(item + '_1') # Decompose the bi-directional links into two uni-directional links. # Add direction to route_id. veh_cap_of_routes = open_data_file_with_header( 'data/vehicle_capacity_of_routes.csv') veh_cap_of_routes = [item[0] for item in veh_cap_of_routes] # 0 # veh_capacity self.links_directional = [] for item in self.links: capacity = int(veh_cap_of_routes[self.routes.index(item[1])]) # Add links for one direction. self.links_directional.append([item[0] + '_0'] + [item[1] + '_0'] + item[2:4] + \ [TRANSIT_TYPE, int(item[5]), LARGE_CONST,capacity,int(item[5])]) # Swap the starting stop and ending stop; add links for another direction temp = item[2] item[2] = item[3] item[3] = temp # Add direction to route_id item[1] += '_1' item[0] += '_1' # Note that transit links have infinite frequrncies; it's the WT links that have finite frequencies. self.links_directional.append(item[0:4] + [ TRANSIT_TYPE, int(item[5]), LARGE_CONST, capacity, int(item[5]) ]) self.links_exp = deepcopy(self.links_directional) self.stops_exp = deepcopy(self.stops) # Add new nodes and links at possible transfer points. # Steps: # 1) For a given directional route, find the set of links that are on # this directional route; # 2) Find the starting stop of this directional route; then sort the set in 1); # 3) Add additional links at trasfer points, depending on: # 3.1) # Used to formulate the link_id for new links. additional_link_count = 1 for route in self.routes_directional: # 1) Find those links that are on current route. links_on_route = [] for i in range(len(self.links_exp)): if self.links_exp[i][1] == route: # Modify the node name of links on routes. self.links_exp[i][2] = self.links_exp[i][2] + '_' + route self.links_exp[i][3] = self.links_exp[i][3] + '_' + route # Add to the links_on_route list. links_on_route.append(self.links_exp[i]) # 2) Find starting stop of this route and sort link set. # Find starting stop # Initialize start_stop_of_route = links_on_route[0][2] flag = 0 while flag == 0: for count in range(len(links_on_route)): # If current start_stop_of_route appears to be ending stop of # some other links ... if links_on_route[count][3] == start_stop_of_route: start_stop_of_route = links_on_route[count][2] break # If this links never happens to be an ending stop ... if count == len(links_on_route) - 1: flag = 1 # Sort links on current route. links_on_route_sorted = [] current_node = start_stop_of_route iteration_count = 1 while links_on_route: for i in range(len(links_on_route)): if links_on_route[i][2] == current_node: links_on_route_sorted.append(links_on_route[i]) current_node = links_on_route[i][3] del links_on_route[i] break iteration_count += 1 if iteration_count == 100000: print(' Links Data Error! Some links are missing!') print(' Traceback: StaticNetwork') links_on_route = [] # 3) Add links and nodes for current route # Note: the additiinal links' cost is set at SMALL_CONST # in order to avoid tie on distance! # Tie happens in step 2 of Spiess' algorithm, when # sort links in desending order according to {cij + uj}. temp_len = len(links_on_route_sorted) for i in range(temp_len): temp_freq = 3600 / float(self.frequencies[self.routes.index( route[0:-2])]) # For each link i, extract the information of the starting nodes: # - the original name (without direction) of the starting stop (original_starting_node); # - the new name of starting stop of this link (directional_starting_node). route_name_len = len(route) + 1 original_starting_node = links_on_route_sorted[i][2][ 0:-route_name_len] directional_starting_node = links_on_route_sorted[i][2] # Add directional node. self.stops_exp.append(directional_starting_node) # If this link is the last link, information concerning the ending nodes # are also extracted for later use: # - the original name (without direction) of the ending stop (original_ending_node); # - the new name of ending stop of this link (directional_ending_node). if i == (temp_len - 1): original_ending_node = links_on_route_sorted[i][3][ 0:-route_name_len] directional_ending_node = links_on_route_sorted[i][3] # Add directional node. self.stops_exp.append(directional_ending_node) # Remember: WT ans WK links should have > 0 small cost! # For the first node on route .. if i == 0: # Add WT link self.links_exp.append(['LA' + str(additional_link_count),route,\ original_starting_node,directional_starting_node,'WT',SMALL_CONST,temp_freq,LARGE_CONST,SMALL_CONST]) additional_link_count += 1 # For intermediate node on route elif i >= 1 and i <= (temp_len - 2): # Add WT and WK links self.links_exp.append(['LA' + str(additional_link_count),route,\ original_starting_node,directional_starting_node,'WT',SMALL_CONST,temp_freq,LARGE_CONST,SMALL_CONST]) additional_link_count += 1 self.links_exp.append(['LA' + str(additional_link_count),route,\ directional_starting_node,original_starting_node,'WK',SMALL_CONST,LARGE_CONST,LARGE_CONST,SMALL_CONST]) additional_link_count += 1 # For the second last and the last node on route elif i == temp_len - 1: self.links_exp.append(['LA' + str(additional_link_count),route,\ original_starting_node,directional_starting_node,'WT',SMALL_CONST,temp_freq,LARGE_CONST,SMALL_CONST]) additional_link_count += 1 self.links_exp.append(['LA' + str(additional_link_count),route,\ directional_starting_node,original_starting_node,'WK',SMALL_CONST,LARGE_CONST,LARGE_CONST,SMALL_CONST]) additional_link_count += 1 # handle last node on the route self.links_exp.append(['LA' + str(additional_link_count),route,\ directional_ending_node,original_ending_node,'WK',SMALL_CONST,LARGE_CONST,LARGE_CONST,SMALL_CONST]) additional_link_count += 1 # print network information if TEST_SN == 1: print(' routes_directional:(length: ' + str(len(self.routes_directional)) + ')') print(self.routes_directional) print() print(' stops: (length: ' + str(len(self.stops)) + ')') print(self.stops) print() print(' stops_exp:(length: ' + str(len(self.stops_exp)) + ')') print(self.stops_exp) print() print(' frequencies:') print(self.frequencies) print() print(' links_directional:(length: ' + str(len(self.links_directional)) + ')') print(self.links_directional) print() print(' links_exp:(length: ' + str(len(self.links_exp)) + ')') print(self.links_exp) print(" A static network has been successfully created!")
def __init__(self): print(' ---------------------------------------------------') print(" Creating a time-expanded network object ...") # Config TEST = int(open_config_file('test_TimeExpandedNetwork')) TRANSIT_TYPE = open_config_file('TRANSIT_TYPE') # T is the time horizon for analysis horizon, with minute as unit; # Horizon start form 0 to (T-1) in time-dependent model. self.T = open_config_file('HORIZON') # Read files from '/data', remove header, decompose elmts. temp = open_data_file_with_header("data/stops.csv") # stop table header: # 1 # stop_id self.stops = [item[0] for item in temp] num_stops = len(self.stops) temp = open_data_file_with_header("data/routes.csv") # routes table header: # 0 # route_id eg. "R1_0" self.routes = [item[0] for item in temp] num_routes = len(self.routes) self.schedules = {} with open("data/schedules.json", encoding="utf8") as f: # stop times dictionary: # key: eg. "R1_0" # item: # 0* 1* 2 3* 4 #trip_id,arrival_time,departure_time,stop_id,stop_sequence self.schedules = json.load(f) if TEST == 1: print(" the horizon (T) is: " + str(self.T)) print(" Stops:") print(self.stops) print(" --------------------------") print(" Transit routes:") print(self.routes) print(" --------------------------") print(" Transit schedules:") print(self.schedules) # Creat links in TE networks according to self.schedule. self.links_exp = [] # Add traveling links. # Import capacity file. veh_cap_of_routes = open_data_file_with_header( 'data/vehicle_capacity_of_routes.csv') # Header: # 0 # veh_capacity # Notice: sequence of routes in cap file must be the same with the seq of routes in routes file. # Create a route list (1st colume in veh_capacity_of_routes) # to pinpoint the place of the corresponding capacity, # since the sort of this table may be different from the self.stop. for key in self.schedules: for i in range(len(self.schedules[key])): # If this is not the end of this schedule ... if i != len(self.schedules[key]) - 1: # If this is not the end of a run's end ... #if int(self.schedules[key][i+1][4]) == int(self.schedules[key][i][4]) + 1: if int(self.schedules[key][i + 1][0]) == int( self.schedules[key][i][0]): starting_time = self.schedules[key][i][1] # starting stop in TE network starting_stop_in_te = self.schedules[key][i][ 3] + '_' + str(starting_time) ending_time = self.schedules[key][i + 1][1] ending_stop_in_te = self.schedules[key][ i + 1][3] + '_' + str(ending_time) if ending_time <= (self.T - 1): # Find the bus route for current link current_route_index = self.routes.index(key) # Find capacity for current link # Note: set to float, since fractional flow is allowed. capacity = float( veh_cap_of_routes[current_route_index][0]) # Creat traveling links in TE network # Notes: # 1)Travel cost is initialized to be the TT; # 2) now the link starting stop and ending stop are stop name; # they will be converted to stop_index later; # 3) "frequency" will be left empty. self.links_exp.append(['', current_route_index, \ starting_stop_in_te, ending_stop_in_te, TRANSIT_TYPE,ending_time - starting_time,\ '', capacity, ending_time - starting_time]) # Add waiting links. for i in range(num_stops): # At the last time T, users no longer need to wait; they "disappear". for t in range(self.T - 1): starting_stop_in_te = self.stops[i] + '_' + str(t) ending_stop_in_te = self.stops[i] + '_' + str(t + 1) # num_routes will be used to label waiting or dummy links! self.links_exp.append(['', num_routes,\ starting_stop_in_te, ending_stop_in_te, 'WT', 1.0, '', float('inf'), 1.0]) # Add index for links. for temp_index in range(len(self.links_exp)): self.links_exp[temp_index][0] = temp_index self.links_exp_char = deepcopy(self.links_exp) if TEST == 1: print(" --------------------------") print(" Links in TE network (links_exp_char):") print(self.links_exp_char) # Create stops in TE networks. temp_stops_exp = [] for i in range(num_stops): for t in range(self.T): temp_stops_exp.append(self.stops[i] + '_' + str(t)) # Find the T&C order for nodes # Initialize temp_links_exp = deepcopy(self.links_exp) self.stops_exp = [] self.stops_exp_2 = [] current_node = temp_stops_exp[0] current_node_index = 0 while len(temp_stops_exp) != 0: # "flag" used to indicate whether this node has been an upstream node # for some link. flag = 0 for i in range(len(temp_links_exp)): if temp_links_exp[i][2] == current_node: current_node = temp_links_exp[i][3] current_node_index = temp_stops_exp.index(current_node) flag = 1 break # If this node has never been an upstream node ... if flag == 0: self.stops_exp.append(current_node) # Delete node whose reverse T&C order has been found. del temp_stops_exp[current_node_index] # Delete all links that end in current node. temp_links_exp = [ item for item in temp_links_exp if item[3] != current_node ] if len(temp_stops_exp) != 0: current_node = temp_stops_exp[0] current_node_index = 0 # Note that above order is reverse T&C order. # Now change it to T&C order. # Note: don't use self.stops_exp = self.stops_exp.reverse(). self.stops_exp.reverse() if TEST == 1: print(" --------------------------") print(" Stops in TE network (sorted in T&C order):") print(self.stops_exp) # Create stops_exp_2. # Find i for node i_t. # Find t for node i_t. for temp_index in range(len(self.stops_exp)): self.stops_exp_2.append([temp_index, \ self.stops.index(self.stops_exp[temp_index].split('_')[0]), \ int(self.stops_exp[temp_index].split('_')[1])]) if TEST == 1: print(" --------------------------") print(" stops_exp_2 is:") print(self.stops_exp_2) # Convert stop name in self.links_exp to stop_index; and add link_index. for temp_index in range(len(self.links_exp)): self.links_exp[temp_index][2] = self.stops_exp.index( self.links_exp[temp_index][2]) self.links_exp[temp_index][3] = self.stops_exp.index( self.links_exp[temp_index][3]) if TEST == 1: print(" --------------------------") print(" List of links (with attributes changed to indices):") print(self.links_exp) print(" A time-expanded network has been successfully created!")
def dynamic_schedule_based_ue_assignment_algorithm_run(): tn = TimeExpandedNetwork() # Option 1)Input manually # Some parameters TEST_LOADED_OD_FLOW = int(open_config_file('test_loaded_od_flow')) TEST_PROB_INITIALIZATION = int( open_config_file('test_prob_initialization')) MAX_NUMBER_OF_ITERATIONS = int( open_config_file('MAX_NUMBER_OF_ITERATIONS_FOR_ASSIGNMENT_MODEL')) DOUBLE_STREAMLINED = int(open_config_file('DOUBLE_STREAMLINED')) ADD_NOISE = int(open_config_file('ADD_NOISE')) num_strategies = MAX_NUMBER_OF_ITERATIONS # Number of stops. num_stops = len(tn.stops) N = len(tn.stops) num_stops_exp = len(tn.stops_exp) # Number of stages in dynamic pogramming # "+ 1" because an additional stage is added when an additional node is added. num_stages = len(tn.stops_exp) + 1 # Time horizon. T = tn.T # Number of bus lines. num_routes = len(tn.routes) # The most number of choices user could have at a node, which equals # the number of routes, adding a waiting link. num_choices = num_routes + 1 # Note: waiting link will has index = num_routes. # Number of arcs. num_links_exp = len(tn.links_exp) print() print(" T: " + str(T)) print(" num_stops: " + str(num_stops)) print(" num_stops_exp: " + str(num_stops_exp)) print(" num_links_exp: " + str(num_links_exp)) print(" num_routes: " + str(num_routes)) print(" num_strategies: " + str(num_strategies)) print(" add noise: " + str(ADD_NOISE)) print(" Find initial od_flow_to_stop_prob...") # Initialize the cost of links for index in range(len(tn.links_exp)): tn.links_exp[index][8] = tn.links_exp[index][5] # Initialize od_flow_to_stop_prob. # Users will follow the path determined by the initial preference set. # No capacity constraints etc. considered. prefer_links_optimal, prefer_probs_optimal = find_initial_strategy(tn) od_flow_to_stop_prob = np.zeros((N, N, T, N, T)) for q_origin in range(N): for r_dest in range(N): if r_dest != q_origin: for h_depart in range(T): # Initialize departure node in TE network. # Notations inherated from dynamic_schedule_based_ue_assignment_algorithm. i = q_origin t = h_depart i_t = tn.stops_exp.index(tn.stops[q_origin] + '_' + str(h_depart)) # coming from route l = num_choices - 1 tau = h_depart arrive_dest_flag = 0 while arrive_dest_flag == 0: if TEST_PROB_INITIALIZATION == 1: print() print(" Current [q,r,h]: " + str([q_origin, r_dest, h_depart]) + " current node: " + str(tn.stops_exp[i_t]) + " - " + str(i_t)) print(" prefer_links_optimal:") print(prefer_links_optimal[r_dest, l, tau, i_t]) print(" prefer_stops_optimal:") print(prefer_stops_optimal[r_dest, l, tau, i_t]) # Update od_flow_to_stop_prob for current node. if q_origin != r_dest: if i == q_origin and t == h_depart: od_flow_to_stop_prob[q_origin, r_dest, h_depart, i, t] = 1.0 if TEST_PROB_INITIALIZATION == 1: print( " Entry count od_flow_to_stop_prob" + str([q_origin, r_dest, h_depart, i, t ]) + " updatd to 1.") if i == r_dest: od_flow_to_stop_prob[q_origin, r_dest, h_depart, i, t] = 1.0 if TEST_PROB_INITIALIZATION == 1: print( " Exit count od_flow_to_stop_prob" + str([q_origin, r_dest, h_depart, i, t ]) + " updatd to 1.") if i != q_origin and i != r_dest and l != ( num_choices - 1): od_flow_to_stop_prob[q_origin, r_dest, h_depart, i, t] = 1.0 if TEST_PROB_INITIALIZATION == 1: print( " Passby count od_flow_to_stop_prob" + str([q_origin, r_dest, h_depart, i, t ]) + " updatd to 1.") # Update arrive_dest_flag if needed. if i == r_dest: arrive_dest_flag == 1 if TEST_PROB_INITIALIZATION == 1: print(" Arrive at destination.") break # Find next node. # If preference set not empty, which means it's able to get to the destination in T; if prefer_links_optimal[r_dest, l, tau, i_t]: link_next = prefer_links_optimal[r_dest, l, tau, i_t][0] l_next = tn.links_exp[link_next][1] i_t_next = tn.links_exp[link_next][3] i_next = tn.stops_exp_2[i_t_next][1] t_next = tn.stops_exp_2[i_t_next][2] if l_next == (num_choices - 1): tau_next = tau else: # Use TT to update tau. tau_next = t_next else: if TEST_PROB_INITIALIZATION == 1: print( " This node cannot reach destination within horizon." ) break # Update node. i_t = i_t_next i = i_next t = t_next l = l_next tau = tau_next del prefer_links_optimal, prefer_probs_optimal # Option 1) Manual Input od_flow = np.zeros((num_stops, num_stops, T)) od_flow[0, 4, 0] = 150 od_flow[1, 4, 0] = 150 # Option 2) Import if TEST_LOADED_OD_FLOW == 1: od_flow = np.load('data/od_flow.npy') print(" Total flow: " + str(od_flow.sum())) if ADD_NOISE == 0: od_flow_to_stop_prob, link_combined_flow = dynamic_schedule_based_ue_assignment_algorithm( tn, od_flow, od_flow_to_stop_prob) else: od_flow_to_stop_prob, link_combined_flow = dynamic_schedule_based_ue_assignment_algorithm_with_noises( tn, od_flow, od_flow_to_stop_prob)