def solve_with_a_star(self):
        path = []
        openList = MinHeap([])
        entryFinder = {}
        initial_cost = self.heuristic[self.startingNode]
        openList.insert(initial_cost, [self.startingNode, []])
        entryFinder[self.startingNode] = 0
        closedList = []
        memory_spend = 0

        for i in range(1, MAX_ATTEMPTS):
            if openList.heap_size is 0:
                raise Exception("Not found a solution")
            else:
                if openList.heap_size > memory_spend:
                    memory_spend = openList.heap_size
                p = openList.extract_min()
                cost_until_now = p[0]
                actual_city = p[1][0]
                if actual_city in entryFinder:
                    entryFinder.pop(actual_city)
                if actual_city in self.objectives:
                    finalPath = p[1][1]
                    finalPath.append(actual_city)
                    print(memory_spend)
                    print(finalPath)
                    print(cost_until_now)
                    return
                adj_cities = self.graph[actual_city]
                closedList.append(actual_city)
                for adj_city in adj_cities:
                    if adj_city not in closedList:
                        gx = (cost_until_now - self.heuristic[actual_city]
                              ) + adj_cities[adj_city]['distance']
                        cost = gx + self.heuristic[adj_city]
                        if adj_city not in entryFinder:
                            path = p[1][1]
                            newPath = list(path)
                            newPath.append(actual_city)
                            openList.insert(cost, [adj_city, newPath])
                            entryFinder[adj_city] = cost
                        else:
                            if cost < entryFinder[adj_city]:
                                path = p[1][1]
                                newPath = list(path)
                                newPath.append(actual_city)
                                for i in range(1, openList.heap_size):
                                    if openList.heap[i][1][0] == adj_city:
                                        openList.heap[i][1][1] = newPath
                                        openList.decrease_priority(i, cost)
                                        entryFinder[adj_city] = cost
                                        break
        raise Exception("Max attempts reached")
Exemple #2
0
def a_star(start_state,
           heuristic_func,
           successors_gen,
           goal_predicate,
           cost_func=lambda *_: 1):
    """
    Generalized implementation of A* search.

    Input:
        start_state:        Initial state
        heuristic_func:     Function of the form (state) -> heuristic value
        successors_gen:     Generator which yields all successors for a given state: 
                                state -> yield successor state
        goal_predicate:     Predicate to test whether the given state is a goal state:
                                state -> True or False

        (Optional)
        cost_func:          Function which returns the cost of a state transition:
                                from_state, to_state -> cost
                            Defaults to a cost of one.
    
    Returns:
        A list of the form 
            [(x0, y0), (x1, y1), ..., (xn, yn)] 
        representing a path from start to end node.
    """
    # Memoization table, maps from state to corresponding node
    memo = {}

    # Initialize containers
    closed = set()
    open_ = MinHeap(key_attr='f')

    # Initialize starting node
    start = initialize_start_node(start_state, heuristic_func)
    open_.insert(start)
    memo[start_state] = start

    # Loop as long as there are nodes to process
    while open_:
        u = open_.extract_min()
        closed.add(u)

        # Test to see if goal state is reached
        if goal_predicate(u.state):
            print("Goal found!")
            return [node.state[1:] for node in create_path_to(u)]

        # Process successor states of current node
        for v_state in successors_gen(u.state):
            # Check if state has been previously encountered, create new by default
            if v_state in memo:
                v = memo[v_state]
            else:
                v = initialize_successor_node(u, v_state, heuristic_func,
                                              cost_func)
                memo[v_state] = v

            # Add to parents' list of successors
            u.successors.append(v)

            # In case of encountering a new node (not opened or closed)
            if v not in open_ and v not in closed:
                attach_and_eval(v, u, heuristic_func, cost_func)
                open_.insert(v)
            # If path is an improvement to previously discovered node
            elif u.g + cost_func(u.state, v.state) < v.g:
                attach_and_eval(v, u, heuristic_func, cost_func)
                # If successor is an internal node
                if v in closed:
                    propagate_path_improvements(v, heuristic_func, cost_func)