示例#1
0
    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
示例#2
0
# 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')
示例#3
0
    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])
示例#7
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
示例#8
0
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")
示例#9
0
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
示例#10
0
    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!")
示例#11
0
    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)