Example #1
0
class Instance(object):
    """
    Instance class representing the TSP Instance
    """
    def __init__(self, nodes, alpha, beta, decay, q):

        # Make a list of nodes as variables which are JSONifiable
        nodes_var = []
        for node in nodes:
            nodes_var.append(vars(node))
        self.nodes = nodes_var

        self.alpha = alpha
        self.beta = beta
        self.decay = decay
        self.q = q
        self.min_pheromone = 0.01
        self.local_deposit = 0.1

        self.distances = []
        self.pheromones = []
        colony = Colony()
        self.ants = colony.ants
        self.shortest_path = colony.shortest_path
        self.min_distance = colony.min_distance

        # Initialise the distances between nodes and pheromone trails
        for i in range(len(nodes)):
            distances = []
            pheromones = []
            for j in range(len(nodes)):
                distances.append(0 if i == j else nodes[i].distance(nodes[j]))
                pheromones.append(self.min_pheromone)
            self.distances.append(distances)
            self.pheromones.append(pheromones)

    def get_path_distance(self, path):
        """
        Returns the total total distance of a path taken
        """
        length = len(path)
        distance = 0
        for i in range(length):
            distance += self.distances[path[i]][path[(i + 1) % length]]
        return distance

    def update_pheromones(self, colony):
        """
        Updates pheromones between nodes globally, a way of letting ants know on future
        generations about the strongest paths to take.
        """

        # Decay all pheromone trails
        for i in range(len(self.nodes)):
            for j in range(len(self.nodes)):
                self.pheromones[i][j] *=(1- self.decay)

        # Add to edge pheromones if edge was part of successful tour
        for ant in colony.ants:
            distance = self.get_path_distance(ant.path)
            if distance <= colony.min_distance:
                for i, j in ant.nodes_traversed():
                    self.pheromones[i][j] += self.q / distance

        # Keep pheromone trails greater than or equal to 0.01, so nodes do not become
        # completely unviable choices.
        for i in range(len(self.nodes)):
            for j in range(len(self.nodes)):
                self.pheromones[i][j] = max(self.pheromones[i][j], self.min_pheromone)



    def aco(self, gens, current_gen, client):
        """
        Returns the generation reached and the shortest path found by the aco
        algorithm along with its distance
        """
        # The time at the start of the algorithm
        time_start = time.time()

        # Initalise the colony and its parameters
        self.colony = Colony()
        self.colony.ants = self.ants
        self.colony.shortest_path = self.shortest_path
        self.colony.min_distance = self.min_distance

        # Initialise an array to be append with nodes
        shortest_path = []

        # Do generations from the current generation to the generation number needed
        for i in range(current_gen, gens):

            # The current time
            time_now = time.time()
            time_elapsed = time_now-time_start
            # If exectutiion time has reached 25 seconds, return result
            if (time_elapsed) > 25:
                break

            # Ants within colony perform their tours
            self.colony.perform_tours(self)

            # Get the shortest tour found by the ants
            shortest_path = self.colony.shortest_path

            # Global update of pheromones
            self.update_pheromones(self.colony)

            # Generation successful, thus increase the generation reached
            gen_reached = i+1

            # Update Instance parameters to be returned to client
            self.shortest_path = shortest_path
            self.min_distance = self.colony.min_distance
            msg = "Generation " + str(i) + " distance " + str(round(self.colony.min_distance, 3)) + " path " + str(shortest_path)

            # Emit a message using SocketIO for a dynamic console
            socketio.emit('my event', msg, room=client)
            socketio.sleep(0.00000000001)

        return gen_reached, shortest_path, self.colony.min_distance