def __init__(self, file, p, traject, timeframe): """Initializes the objects needed for the algorithm""" self.trains = copy.deepcopy(traject) self.proportion = p self.timeframe = timeframe # reads connections read = Read(file) self.stations, self.cdict, self.clist, self.clist2 = read.readConnections( ) # initialise time self.time = 0 # adds time of all trains in planning for train in self.trains.values(): self.time += train.time # calculates score from planning self.score = formula(p, len(self.trains.keys()), self.time)
def rerun_train(self): # chooses a random train from the planning key = random.choice(list(self.trains.keys())) train = self.trains[key] # make empty list of connections used connections_used = [] # adds all other trains to connections used for traject in self.trains.values(): if traject is not train: for c in traject.connections: if (c.text() not in connections_used and changeDirection( c.text()) not in connections_used): connections_used.append(c.text()) new_train = Traject() # find unused track to start the train on while True: start = random.choice(self.clist) # only stops looking when it finds an unused connection if start not in connections_used: break # add starting connection new_train.addConnection(self.cdict[str(start)], self.cdict[str(start)].time, self.timeframe) while True: # find the current station of the traject destination = traject.connections[-1].destination # find the previous station of the traject origin = traject.connections[-1].origin # check whether there is an option to expand the traject further if fastestConnection(self.cdict, destination, origin) != None: # add the connection with the shortest time to the traject new_connection = fastestConnection(self.cdict, destination, origin) if self.cdict[new_connection] in traject.connections: break traject.addConnection(self.cdict[new_connection], self.cdict[new_connection].time, self.timeframe) # stops the process when done else: break # adds connections in new train to connections used for k in new_train.connections: if k.text() not in connections_used and changeDirection( k.text()) not in connections_used: connections_used.append(k.text) # define the alternative plan new_plan = copy.deepcopy(self.trains) # replace train with the new train new_plan[key] = new_train # calculates new p new_p = 2 * len(connections_used) / len(self.clist) new_time = 0 for train in new_plan.values(): new_time += train.time # calculates new score new_score = formula(new_p, len(new_plan.keys()), new_time) # changes train to new train if score higher if new_score > self.score: self.trains = copy.deepcopy(new_plan) self.score = new_score self.time = new_time return new_score
def run(self): """Returns a solution for the problem by using a greedy algorithm that takes the fastest option.""" # save traject objects in dictionairy trajecten = {} # total amount of connections where a to b and b to a are considered the same count of all the elements in list total = len(self.connectionslist) / 2 # a list which will be filled with the connections that are used in all tracks connections_used = [] # total minutes of all the tracks together total_minutes = 0 # create track object traject = Traject() # create a new track object for the amount of trains allowed for i in range(self.trains): # create track object traject = Traject() # initialize starting point, not a used connection while True: start = random.choice(self.connectionslist) if start not in connections_used: break # add starting connection to the track traject.addConnection(self.connections[str(start)], self.connections[str(start)].time, self.timeframe) # for loop that adds connections to the track object for j in range(0, 20): # find the current station of the track new_origin = traject.connections[-1].destination # find the previous station of the track previous_station = traject.connections[-1].origin # check whether there is an option to expand the track further if fastestConnection(self.connections, new_origin, previous_station) != None: # add the connection with the shortest time to the track new_connection = fastestConnection(self.connections, new_origin, previous_station) traject.addConnection( self.connections[new_connection], self.connections[new_connection].time, self.timeframe) # save track in the tracks dictionairy trajecten[i] = traject total_minutes += traject.time # update the list of connections used for every new connection that had not been used before for k in traject.connections: if k.text() not in connections_used and changeDirection( k.text()) not in connections_used: connections_used.append(k.text()) # calculate p p = len(connections_used) / total train_used = i + 1 score = formula(p, self.trains, total_minutes) return trajecten, p, total_minutes, score, train_used
def run(self): """Returns an efficient solution""" # keep track of how many trains will be used trains_used = 0 # total amount of connections total = len(self.clist) # save track objects in dictionairy trajecten = {} # keep track of the connections used in the whole timetable connections_used = [] # keep track of the total time of all the track object total_minutes = 0 # when current score is lower then previous score, it will be # considered a failed attempt failed_attemps = 0 while True: # ratio connection used to total in current state current_p = (len(connections_used)) / total # current score current_score = formula(current_p, trains_used , total_minutes) # how many connections, that are not used before, will the # new track have count_new_connections = 0 traject = Traject() while True: # choose random begin connection start = random.choice(self.clist) # however, make sure that this connenction is not used before if (start not in connections_used and changeDirection(start) not in connections_used): break # add starting connection to the traject traject.addConnection(self.connections[start], self.connections[start].time, self.timeframe) while True: # find the current station of the traject new_origin = traject.connections[-1].destination # keep track how much time is left within the track time_left = self.timeframe - traject.time # save the current connections made in a list traject_connections = [] for each in traject.connections: traject_connections.append(each.text()) traject_connections.append(changeDirection(each.text())) # check which connection is the best to be made best_option = bestConnection(new_origin, time_left, self.connections, connections_used, traject_connections) # if connection is found, add to track if best_option != None: traject.addConnection(self.connections[best_option], self.connections[best_option].time, self.timeframe) else: break # count how many unused connections are found in the new track for k in traject.connections: if k.text() not in connections_used: count_new_connections += 1 # with new connections found, the new p: possible_p = ((len(connections_used) + count_new_connections) / total) # calculate the possible score score = formula(possible_p, trains_used + 1, total_minutes + traject.time) # when the score is indeed higher than before, add the track if score > current_score and trains_used != self.trains: trajecten[trains_used] = traject trains_used += 1 total_minutes += traject.time for k in traject.connections: if k.text() not in connections_used: connections_used.append(k.text()) connections_used.append(changeDirection(k.text())) # otherwise the track won't be added and a the programs tries to # find a better one else: failed_attemps +=1 # if, after 10 failed attemps, no track is found that improves # the score we stop if failed_attemps == self.failed_attemps: break # final p and score p = len(connections_used) / total score = formula(p, trains_used, total_minutes) return trajecten, p, score, trains_used
def run(self): """Returns a random solution for the problem""" # how many connections are there in total total = len(self.clist) / 2 while True: # a dictionary filled with the tracks that are made trajecten = {} # a list which will be filled with the connections that are used connections_used = [] # total minutes of all the tracks together total_minutes = 0 # chooses a random amount of trains within the given boundries randtrains = random.randrange(self.trains) for i in range(0, randtrains): traject = Traject() # choose a random begin connection start = random.choice(self.clist) # add the connection to the current track traject.addConnection(self.connections[start], self.connections[start].time, self.timeframe) while True: # new beginning point new_origin = traject.connections[-1].destination time_left = self.timeframe - traject.time # possible connections from the current origin options = optionsTime(new_origin, time_left, self.connections) # add the possibility of not adding a connection options.append(None) new_connection = random.choice(options) # choos a random connection and add this to the track, if there are any options available if new_connection != None: traject.addConnection( self.connections[new_connection], self.connections[new_connection].time, self.timeframe) else: break # save the track trajecten[i] = traject # add the amount of minutes total_minutes += traject.time # for each connection used, add to list connection_used, if connection wasn't used before for k in traject.connections: if k.text() not in connections_used and changeDirection( k.text()) not in connections_used: connections_used.append(k.text()) # calculate p p = len(connections_used) / total # calculate score score = formula(p, randtrains, total_minutes) return trajecten, p, score, randtrains
def run(self): """Returns the tracks that are covered, p, score and amount of trais used""" # a list which will be filled with the connections that are used connections_used = [] # a dictionary, with the key being the station and the value is the # amount of connections of this station stationsvalues = {} # a dictionary filled with the tracks that are made trajecten = {} # total minutes of all the tracks together total_minutes = 0 # amount of connections possible, used for calculating p total_connections = len(self.connections)/2 # fills the stationsvalues dictionary for station in self.stations: con_values = len(self.stations[station]) if station not in stationsvalues: stationsvalues[station] = [] stationsvalues[station].append(con_values) # sorts the stationvalues dictionary in ascending order sort_con = sorted(stationsvalues.items(), key=lambda kv: (kv[1], kv[0])) scorelist = {} for i in range(1, self.trains): traject = Traject() # searches for a station with the least connections and not used yet while True: try: check = f"{sort_con[0][0]}-{self.stations[sort_con[0][0]][0][0]}" except: check = 'not valid' break # if the connection is used, drop this connection from the dictionary if check in connections_used or changeDirection(check) in connections_used: sort_con.pop(0) # otherwise use this connection else: break if check == 'not valid': break # add the connection to the track origin = sort_con[0][0] destination = self.stations[origin][0][0] traject.addConnection(self.connections[f"{origin}-{destination}"], self.stations[origin][0][1], self.timeframe) # append track of the used connections, so it won't be used a second time connections_used.append(f"{origin}-{destination}") # delete the connection from the sorted dictionary, so it wont be used a second time as a start connection sort_con.pop(0) # after the first connection is found, finish the track while True: # we pick the fastest connection new_connection = fastestConnection(self.connections, destination, origin) if new_connection != None: # if the connection is already in the current track, stop the train if self.connections[new_connection] in traject.connections: break # otherwise add the connection to the current track traject.addConnection(self.connections[new_connection], self.connections[new_connection].time, self.timeframe) if new_connection not in connections_used: connections_used.append(new_connection) # if there is no new connection stop the current track else: break # extracts destination and origin from the connection object destination = traject.connections[-1].destination origin = traject.connections[-1].origin # if the total time of the track is bigger than the allowed timeframe, stop the current track if traject.time + self.connections[new_connection].time >= self.timeframe: break # update the total minutes total_minutes += traject.time # save track trajecten[i -1] = traject # save amount of trains used train_used = i + 1 # calculate p p = (len(connections_used)-i)/total_connections # score after track is added score_i = formula(p, train_used, total_minutes) if i not in scorelist: scorelist[i] = [] scorelist[i].append(score_i) train_used= max(scorelist.items(), key=operator.itemgetter(1))[0] score = max(scorelist.values())[0] return trajecten, p, score, train_used
def run(self): """Returns the tracks, p, score and trains that are used, found with the help of Kruskal""" # dictionary that will be filled with the tracks that are made trajecten = {} # total minutes of all the tracks together total_minutes = 0 # amount of connections available total_connections = len(self.clist) / 2 # a list which will be filled with the connections that are used in all tracks connections_used = [] # the connection list sorted by time in ascending order graph = sorted(self.clist2, key=lambda item: item[2]) for i in range(0, self.trains): # origin, destination, time u, v, w = graph[0] # create track object traject = Traject() # add first, with the least time, connection traject.addConnection(self.connections[f"{u}-{v}"], w, self.timeframe) connections_used.append(self.connections[f"{u}-{v}"]) # remove from graph so it won't be used again graph.remove([u, v, w]) graph.remove([v, u, w]) while True: # build the track from first given connection new_origin = traject.connections[-1].destination previous_station = traject.connections[-1].origin # find options that are allowed to use options = findConnections(new_origin, previous_station, self.connections) useful_options = usefulConnections(new_origin, options, connections_used, traject.time, self.timeframe, self.connections) # with the found options, find shortest option new_connection = self.shortest(useful_options, self.connections) try: time_new_connection = self.connections[new_connection].time except: pass if new_connection != None: # add connection to the current track traject.addConnection(self.connections[new_connection], time_new_connection, self.timeframe) # update the list of connections used for every new # connection that had not been used before if (new_connection not in connections_used and changeDirection(new_connection) not in connections_used): connections_used.append(new_connection) try: # if newconnection is still in graph, remove this from # graph graph.remove([ new_origin, traject.connections[-1].destination, int(time_new_connection) ]) graph.remove([ traject.connections[-1].destination, new_origin, int(time_new_connection) ]) except: pass else: break # keep adding connections untill track is at the maximum of timeframe if traject.time + time_new_connection > self.timeframe: break # update the situation graph = sorted(graph, key=lambda item: item[2]) trajecten[i] = traject total_minutes += traject.time trains_used = i # calculate the score in the final situation p = (len(connections_used) - trains_used) / total_connections score = formula(p, self.trains, total_minutes) return trajecten, p, score, trains_used