예제 #1
0
def UCS(initial_state):
    '''Uniform Cost Search. This is the actual algorithm.'''
    global g, COUNT, BACKLINKS, MAX_OPEN_LENGTH, CLOSED, TOTAL_COST
    CLOSED = []
    BACKLINKS[initial_state] = None
    # The "Step" comments below help relate UCS's implementation to
    # those of Depth-First Search and Breadth-First Search.

    # STEP 1a. Put the start state on a priority queue called OPEN
    OPEN = PriorityQueue()
    OPEN.insert(initial_state, 0)
    # STEP 1b. Assign g=0 to the start state.
    g[initial_state] = 0.0
    cost_so_far = g[initial_state]

    # STEP 2. If OPEN is empty, output “DONE” and stop.
    #   while False: # ***STUDENTS CHANGE THIS CONDITION***
    while OPEN != []:
        # LEAVE THE FOLLOWING CODE IN PLACE TO INSTRUMENT AND/OR DEBUG YOUR IMPLEMENTATION
        if VERBOSE: report(OPEN, CLOSED, COUNT)
        if len(OPEN) > MAX_OPEN_LENGTH: MAX_OPEN_LENGTH = len(OPEN)

        # STEP 3. Select the state on OPEN having lowest priority value and call it S.
        #         Delete S from OPEN.
        #         Put S on CLOSED.
        #         If S is a goal state, output its description
        (S, P) = OPEN.delete_min()
        cost_so_far += P
        g[S] = cost_so_far
        # print(f"currently at {S.name} ")
        # print(f"cost from {initial_state.name} to {S.name} = {cost_so_far}")
        # print("In Step 3, returned from OPEN.delete_min with results (S,P)= \n", (str(S), P))

        # print("BACKLINKS = ")
        # for state in BACKLINKS.keys():
        #   print("parent = " + str(BACKLINKS.get(state)) + ", child = " + str(state))

        CLOSED.append(S)

        if Problem.GOAL_TEST(S):
            print("\n" + Problem.GOAL_MESSAGE_FUNCTION(S) + "\n")

            # handling backtracing
            SOLUTION_PATH = [str(s)
                             for s in backtrace(S)]  # should return a list
            print(f"Solution path = {SOLUTION_PATH}")
            print('Length of solution path found: ' +
                  str(len(SOLUTION_PATH) - 1) + ' edges')

            # handling total cost
            TOTAL_COST = g[S]
            print("TOTAL_COST = " + str(TOTAL_COST))

            return
        COUNT += 1
        print("EXPANDING = ", S.name)

        # STEP 4. Generate each successor of S
        #         and if it is already on CLOSED, delete the new instance.
        successors = []
        for op in Problem.OPERATORS:
            if op.precond(S):
                new_state = op.state_transf(S)
                priority = cost_so_far + new_state.edge_distance(S)

                # if successor is not on CLOSED and OPEN, add to successors
                if not (new_state in CLOSED) and not (new_state in OPEN):
                    successors.append((new_state, priority))
                    BACKLINKS[new_state] = S
                else:
                    if new_state in OPEN:
                        if OPEN[new_state] > priority:
                            OPEN.__delitem__(new_state)
                            OPEN.insert(new_state, priority)
                            # print(f"PREVIOUS BACKLINK FOR {new_state} = {BACKLINKS[new_state].name}")
                            BACKLINKS[new_state] = S
                            # print(f"UPDATING BACKLINK FOR {new_state} = {BACKLINKS[new_state].name}")
                            # print(f"UPDATING PRIORITY FOR {new_state} = {OPEN[new_state]}")
                    elif new_state in CLOSED:
                        # If sj occurs on CLOSED, and its new distance is smaller than its old distance,
                        # then it is taken off of CLOSED, put back on OPEN, but with the new, smaller distance.
                        for item in CLOSED:
                            if item == new_state:
                                old_distance = g[item]
                                if old_distance > priority:
                                    CLOSED.remove(item)
                                    # print(f"STATE {new_state} IS ON CLOSED.")
                                    # print(f"OLD DISTANCE = {old_distance} vs NEW DISTANCE = {new_distance}")
                                    # print(f"CURRENT CLOSED = {str(CLOSED)}")
                                    OPEN.insert(new_state, priority)
                                    BACKLINKS[new_state] = S

        for (s, p) in successors:
            OPEN.insert(s, p)

        print_state_queue("OPEN", OPEN)
        # print("CLOSED: [ ", end="")
        # for state in CLOSED:
        #     print(state.name, end=" ")
        # print("]")
        cost_so_far -= P  # reset cost_so_far to current shortest path
    # STEP 6. Go to Step 2.
    return None  # No more states on OPEN, and no goal reached.
예제 #2
0
def AStar(initial_state):
    global g, COUNT, BACKLINKS, MAX_OPEN_LENGTH, CLOSED, TOTAL_COST
    CLOSED = []
    BACKLINKS[initial_state] = None

    # Put the start state on a priority queue called OPEN
    OPEN = PriorityQueue()

    g[initial_state] = 0.0
    f = g[initial_state] + h(initial_state)
    print("INITIAL STATE HAS F VALUE OF " + str(f))
    OPEN.insert(initial_state, f)

    while OPEN != []:
        if VERBOSE:
            report(OPEN, CLOSED, COUNT)

        if len(OPEN) > MAX_OPEN_LENGTH:
            MAX_OPEN_LENGTH = len(OPEN)

        # STEP 3. Select the state on OPEN having lowest priority value and call it S.
        #         Delete S from OPEN.
        #         Put S on CLOSED.
        #         If S is a goal state, output its description
        (S, P) = OPEN.delete_min()
        # P is the cost from starting state to S
        # print(f"S IS {S.name}")
        # print(f"G[S] IS {g[S]} WHICH REFLECTS THE COST TO GET FROM {initial_state.name} TO S")
        # print(f"H[S] IS {h(S)}")
        # print(f"F[S] IS {P}")
        # print(f"THE PRIORITY FOR S IS {P} WHICH REFLECTS THE COST TO GET FROM {initial_state.name} TO GOAL")
        # print("In Step 3, returned from OPEN.delete_min with results (S,P)= ", (str(S), P))

        # print("BACKLINKS = ")
        # for state in BACKLINKS.keys():
        #   print("parent = " + str(BACKLINKS.get(state)) + ", child = " + str(state))

        # CLOSED.append((S, P))
        CLOSED.append(S)

        if Problem.GOAL_TEST(S):
            print("\n" + Problem.GOAL_MESSAGE_FUNCTION(S) + "\n")

            # handling backtracing
            SOLUTION_PATH = [str(s)
                             for s in backtrace(S)]  # should return a list
            print(f"Solution path = {SOLUTION_PATH}")
            print('Length of solution path found: ' +
                  str(len(SOLUTION_PATH) - 1) + ' edges')

            # handling total cost
            TOTAL_COST = P
            print("TOTAL_COST = " + str(TOTAL_COST))

            return
        COUNT += 1

        # STEP 4. Generate each successor of S
        #         and if it is already on CLOSED, delete the new instance.
        successors = []
        for op in Problem.OPERATORS:
            if op.precond(S):
                new_state = op.state_transf(S)

                # h(curr_state) = an estimate of the distance between curr_state and GOAL
                temp_g = g[S] + new_state.edge_distance(S)
                # f = g[new_state] + h(new_state)
                f = temp_g + h(new_state)

                # pair at hand
                # (new_state, f[new_state])

                # print(f"\tCHILD OF {S.name} = {new_state}; THE COST TO GET FROM INITIAL {initial_state} TO GOAL THROUGH "
                # f"{new_state.name} IS g=g[old]={g[S]} + actual edge weight={new_state.edge_distance(S)} + h={h(new_state)} = f={f[new_state]}")

                successors.append((new_state, f))
                # print(f"\tCHILD OF {S.name} =  {new_state.name} POINTS TO PARENT NODE {S.name}")

                # if there is new_state on CLOSED (for any priority q):
                # for i in range(len(CLOSED)):
                for closed_state in CLOSED:
                    # closed_state = CLOSED[i][0]
                    # q = CLOSED[i][1]
                    # closed_state = CLOSED[i]
                    q = g[closed_state] + h(closed_state)

                    if new_state == closed_state:
                        if f > q:
                            successors.remove((new_state, f))
                            # print(f"\tREMOVED FROM SUCCESSOR... {new_state.name}'s priority in CLOSED and is more expensive than q")

                        # if f(new_state) is smaller than or equal to q, then remove [s', q] from CLOSED.
                        # if f[new_state] <= q:
                        if f <= q:
                            CLOSED.remove(new_state)
                            BACKLINKS[new_state] = S
                            g[new_state] = temp_g
                            # print(f"\tREMOVED FROM CLOSED... {new_state.name}'s priority in CLOSED and is smaller than or equal to q")
                            # print(f"\tCLOSED =", end="")
                            # for state in CLOSED:
                            #     print(f"({state}), ", end="")
                            # print("\n")

                # if there is new_state on OPEN (for any priority q):
                if new_state in OPEN:
                    q = OPEN[new_state]
                    # if f(new_state) is more expensive than q, then remove[s, f(s')] from successors.
                    # if f[new_state] > q:
                    if f > q:
                        successors.remove((new_state, f))
                        # print(f"\tREMOVED FROM SUCCESSOR... {new_state.name}'s priority in OPEN and is more expensive than q")

                    # if f(new_state) is less expensive or equal to q, then remove [s', q] from OPEN.
                    # if f[new_state] <= q:
                    if f <= q:
                        OPEN.__delitem__(new_state)
                        # BACKLINKS[new_state] = S
                        g[new_state] = temp_g
                        BACKLINKS[new_state] = S
                        # print(f"\tREMOVED FROM OPEN... {new_state.name}'s priority in OPEN and is smaller than or equal to q")
                        # print(f"\tNEW PARENT NODE FOR {new_state.name} = {BACKLINKS[new_state].name}")

                if new_state not in CLOSED and OPEN.__contains__(
                        new_state) is False:
                    g[new_state] = temp_g
                    BACKLINKS[new_state] = S
        print()

        for (s, p) in successors:
            OPEN.insert(s, p)
            # BACKLINKS[s] = S

        print_state_queue("OPEN", OPEN)

        # print("CLOSED: [ ", end="")
        # for (state, priority) in CLOSED:
        # print(f"({state.name}, {priority})", end=" ")
        # print("]")

        # cost_so_far -= P  # reset cost_so_far to current shortest path
    # STEP 6. Go to Step 2.
    return None  # No more states on OPEN, and no goal reached.