Exemplo n.º 1
0
    def _init_population(self):
        """Initializes population by creating specified number of random paths.
        """

        self._population.clear()
        for _ in range(self.population_size):
            path = Path(self.tsp.dimension + 1)
            path.path = list(range(self.tsp.dimension)) + [0]
            path.shuffle(1, -1)
            path.distance = self.tsp.path_dist(path)
            self._population.append(path)

        self._population.sort(key=lambda p: p.distance)
Exemplo n.º 2
0
    def test_shuffle(self):
        data = [([0, 1, 2, 3, 4, 5, 6, 7], 2, 5),
                ([0, 1, 2, 3, 3, 5, 6, 0], 1, -1), ([5, 4, 3, 2, 1], 0, 4),
                ([1, 2, 3], 0, 2), ([], 0, 0)]

        for p, i, j in data:
            with self.subTest(path=p, i=i, j=j):
                path = Path(path=deepcopy(p))
                path.shuffle(i, j)

                # Make sure no elements are lost or added
                for n in p:
                    self.assertEqual(path.path.count(n), p.count(n))

                # Compare slices that shouldn't be shuffled
                self.assertListEqual(path[0:i], p[0:i])
                self.assertListEqual(path[j:-1], p[j:-1])
Exemplo n.º 3
0
    def solve(self, tsp, steps=True):
        # Make sure given argument is of correct type
        if not isinstance(tsp, TSP):
            raise TypeError('solve() argument has to be of type \'TSP\'')
        self.tsp = tsp

        # Total number of iterations or time for calculating progress
        if steps:
            current = 0
            iters = log(self.end_temp / self.init_temp, 1 - self.cooling_rate)
            total = self.run_time if self.run_time else iters

        # Start with random path
        cur_path = Path(self.tsp.dimension + 1)
        cur_path.path = list(range(len(cur_path) - 1)) + [0]
        cur_path.shuffle(1, -1)
        cur_path.distance = self.tsp.path_dist(cur_path)

        # And set it as current minimum
        min_path = deepcopy(cur_path)

        # Start the timer
        self._start_timer()

        # Init temperature
        temp = self.init_temp
        # Repeat as long as system temperature is higher than minimum
        while True:
            # Update iteration counter ro time counterif running in step mode
            if steps:
                current = self._time_ms() if self.run_time else current + 1

            # Get random neighbour of current path
            new_path = self._rand_neigh(cur_path)

            # Difference between current and new path
            delta_dist = new_path.distance - cur_path.distance

            # If it's shorter or equal
            if delta_dist <= 0:
                # If it's shorter set it as current minimum
                if new_path.distance < min_path.distance:
                    min_path = deepcopy(new_path)
                # Set new path as current path
                cur_path = deepcopy(new_path)
            elif exp(-delta_dist / temp) > random():
                # If path is longer accept it with random probability
                cur_path = deepcopy(new_path)

            # Cooling down
            temp *= 1 - self.cooling_rate

            # Terminate search after reaching end temperature
            if not self.run_time and temp < self.end_temp:
                break

            # Terminate search after exceeding specified runtime
            # We use `total` to not have to convert to nanoseconds every time
            if self.run_time and self._time_ms() >= self.run_time:
                break

            # Report current solver state
            if steps:
                yield SolverState(self._time(), current / total,
                                  deepcopy(new_path), deepcopy(min_path))

        yield SolverState(self._time(), 1, None, deepcopy(min_path), True)