def generate_initial_solution(self, current_state):
        """
        Makes a random initial solution to start with by populating with whatever swaps possible

        :param current_state: State, the current state of mapping and progress
        :return: list, initial solution as boolean array of whether to swap each node
        """

        force_gates_action = static_heuristics.generate_force_gates_action(
            self.environment, current_state, version=3)

        if force_gates_action is None:
            num_edges = len(self.environment.edge_list)
            initial_solution = [0] * num_edges
            protected_mask = self.generate_protected_mask(current_state[3])

            available_edges = action_edge_translation.swappable_edges(
                initial_solution, current_state, protected_mask,
                self.environment.edge_list, self.environment.number_of_nodes)

            if not available_edges:
                return initial_solution, "None", protected_mask

            edge_index_to_swap = random.sample(available_edges, 1)[0]

            initial_solution[edge_index_to_swap] = (
                initial_solution[edge_index_to_swap] + 1) % 2

            return initial_solution, "Random", protected_mask
        else:
            return list(force_gates_action[0]), "Forced", force_gates_action[1]
Beispiel #2
0
    def get_neighbour_solution(self, current_solution, current_state,
                               forced_mask):
        """
        Get a solution neighboring current, that is one swap inserted
        :param current_solution: list of edges to swap, current solution to start with
        :param current_state: State, the current state of mapping and progress
        :param forced_mask: list, which edges cannot be swapped
        :return: list, neighbor solution
        """
        neighbour_solution = copy.copy(current_solution)
        edge_list = self.environment.edge_list
        n_nodes = self.environment.number_of_nodes

        available_edges = action_edge_translation.swappable_edges(
            neighbour_solution, current_state, forced_mask, edge_list, n_nodes)

        if not available_edges:
            exit("Ran out of edges to swap")

        edge_index_to_swap = random.sample(available_edges, 1)[0]

        neighbour_solution[edge_index_to_swap] = (
            neighbour_solution[edge_index_to_swap] + 1) % 2

        if self.safety_checks_on and not self.check_valid_solution(
                neighbour_solution, forced_mask):
            exit("Solution not safe")

        return neighbour_solution
    def simulated_annealing(self, current_state, action_chooser='model'):
        current_solution, method, forced_mask = self.generate_initial_solution(current_state)

        # print("Base action:")
        # print([(current_state[1][current_state[0][x]], current_state[1][current_state[0][y]]) for (_,(x,y)) in filter(lambda p: current_solution[p[0]] == 1, enumerate(self.environment.edge_list))])
        # print("Can't move:")
        # print([(current_state[1][current_state[0][x]], current_state[1][current_state[0][y]]) for (_,(x,y)) in filter(lambda p: forced_mask[p[0]] == 1, enumerate(self.environment.edge_list))])
        # print("Can move:")
        # print([(current_state[1][current_state[0][x]], current_state[1][current_state[0][y]]) for (_,(x,y)) in filter(lambda p: forced_mask[p[0]] == 0, enumerate(self.environment.edge_list))])

        available_edges = action_edge_translation.swappable_edges(current_solution, current_state, forced_mask, self.environment.edge_list, self.environment.number_of_nodes)

        if not available_edges or current_solution == [0]*len(self.environment.edge_list):
            # There are no actions possible
            # Often happens when only one gate is left, and it's already been scheduled
            return current_solution, -np.inf

        T = self.initial_temperature
        current_energy = self.get_energy(current_solution, current_state=current_state, action_chooser=action_chooser)

        best_solution = copy.copy(current_solution) #.copy()
        best_energy = current_energy

        iterations_since_best = 0

        while T > self.min_temperature:
            if self.speed_over_optimality and iterations_since_best > 40:
                break

            new_solution = self.get_neighbour_solution(current_solution, current_state, forced_mask)
            new_energy = self.get_energy(new_solution, current_state=current_state, action_chooser=action_chooser)
            accept_prob = self.acceptance_probability(current_energy, new_energy, T)
            # print(accept_prob)

            if accept_prob > random.random():
                current_solution = new_solution
                current_energy = new_energy

                # Save best solution, so it can be returned if algorithm terminates at a sub-optimal solution
                if current_energy < best_energy:
                    best_solution = copy.copy(current_solution) #.copy()
                    best_energy = current_energy
                    # intervals.append(iterations_since_best)
                    iterations_since_best = 0

            T = T * self.cooling_multiplier
            iterations_since_best += 1

        if method == "Forced":
            # i.e. we ensure this is chosen, and not Best Effort
            best_energy = -np.inf

        # print("Best solution: ", [self.environment.edge_list[e] for e in np.where(np.array(best_solution) == 1)[0]])
        # print("Energy: ", best_energy)
        # print()

        # intervals.append(iterations_since_best)
        # print("Intervals: ", intervals)

        return best_solution, best_energy
    def generate_initial_solution(self, current_state, forced_mask):
        num_edges = len(self.environment.edge_list)
        initial_solution = [0] * num_edges

        available_edges = action_edge_translation.swappable_edges(
            initial_solution, current_state, forced_mask,
            self.environment.edge_list, self.environment.number_of_nodes)

        if not available_edges:
            return initial_solution

        edge_index_to_swap = random.sample(available_edges, 1)[0]

        initial_solution[edge_index_to_swap] = (
            initial_solution[edge_index_to_swap] + 1) % 2

        return initial_solution
    def simulated_annealing(self, current_state, action_chooser='model'):
        current_solution, method, forced_mask = self.generate_initial_solution(
            current_state)

        available_edges = action_edge_translation.swappable_edges(
            current_solution, current_state, forced_mask,
            self.environment.edge_list, self.environment.number_of_nodes)

        if not available_edges or current_solution == [0] * len(
                self.environment.edge_list):
            # There are no actions possible
            # Often happens when only one gate is left, and it's already been scheduled
            return current_solution, -np.inf

        return super()._simulated_annealing(current_solution, forced_mask,
                                            current_state, action_chooser,
                                            None)
    def get_neighbour_solution(self, current_solution, current_state, forced_mask):
        neighbour_solution = copy.copy(current_solution)
        edge_list = self.environment.edge_list
        n_nodes = self.environment.number_of_nodes

        available_edges = action_edge_translation.swappable_edges(neighbour_solution, current_state, forced_mask, edge_list, n_nodes)

        if not available_edges:
            exit("Ran out of edges to swap")

        edge_index_to_swap = random.sample(available_edges, 1)[0]

        neighbour_solution[edge_index_to_swap] = (neighbour_solution[edge_index_to_swap] + 1) % 2

        if self.safety_checks_on and not self.check_valid_solution(neighbour_solution, forced_mask):
            exit("Solution not safe")

        return neighbour_solution
    def generate_initial_solution(self, current_state):
        protected_nodes = current_state[3]

        force_gates_action = static_heuristics.generate_force_gates_action(self.environment, current_state, version=3)

        if force_gates_action is None:
            num_edges = len(self.environment.edge_list)
            initial_solution = [0]*num_edges
            protected_mask = self.generate_protected_mask(current_state[3])

            available_edges = action_edge_translation.swappable_edges(initial_solution, current_state, protected_mask, self.environment.edge_list, self.environment.number_of_nodes)

            if not available_edges:
                return initial_solution, "None", protected_mask

            edge_index_to_swap = random.sample(available_edges, 1)[0]

            initial_solution[edge_index_to_swap] = (initial_solution[edge_index_to_swap] + 1) % 2

            return initial_solution, "Random", protected_mask
        else:
            return list(force_gates_action[0]), "Forced", force_gates_action[1]
    def get_neighbour_solution(self, current_solution, current_state,
                               forced_mask):
        neighbour_solution = copy.copy(current_solution)
        edge_list = self.environment.edge_list
        n_nodes = self.environment.number_of_nodes

        available_edges = action_edge_translation.swappable_edges(
            neighbour_solution, current_state, forced_mask, edge_list, n_nodes)

        if not available_edges:
            exit("Ran out of edges to swap")

        edge_index_to_swap = random.sample(available_edges, 1)[0]

        neighbour_solution[edge_index_to_swap] = (
            neighbour_solution[edge_index_to_swap] + 1) % 2

        if self.safety_checks_on and not self.check_valid_solution(
                neighbour_solution, forced_mask):
            print([
                self.environment.edge_list[e]
                for e in np.where(np.array(forced_mask) == 1)[0]
            ])
            print([
                self.environment.edge_list[e]
                for e in np.where(np.array(neighbour_solution) == 1)[0]
            ])
            exit("Solution not safe")

        # print("Current solution:")
        # print([self.environment.edge_list[e] for e in np.where(np.array(current_solution) == 1)[0]])
        # print("Available edges:")
        # print([self.environment.edge_list[e] for e in available_edges])
        # print("Neighbour solution:")
        # print([self.environment.edge_list[e] for e in np.where(np.array(neighbour_solution) == 1)[0]])

        return neighbour_solution
    def generate_initial_solution(self, current_state, forced_mask):
        """
        Makes a random initial solution to start with by populating with whatever swaps possible

        :param current_state: State, the current state of mapping and progress
        :param forced_mask: list, mask of edges that are blocked
        :return: list, initial solution as boolean array of whether to swap each node
        """
        num_edges = len(self.environment.edge_list)
        initial_solution = [0] * num_edges

        available_edges = action_edge_translation.swappable_edges(
            initial_solution, current_state, forced_mask,
            self.environment.edge_list, self.environment.number_of_nodes)

        if not available_edges:
            return initial_solution

        edge_index_to_swap = random.sample(available_edges, 1)[0]

        initial_solution[edge_index_to_swap] = (
            initial_solution[edge_index_to_swap] + 1) % 2

        return initial_solution