How to implement Floyd Warshall on a grid?

252 Views Asked by At

just started learning some search algorithms. So I've kinda hit a roadblock (in concept too) about the Floyd Warshall's algorithm for the shortest path. The problem is that I've been given a grid with randomly generated obstacles and I've got to locate the shortest path from start to finish. Now the algorithm does work with graphs, but with grids I'm not very sure.

I'm referencing AIMA's code for uninformed search.

class Problem(object):
    """The abstract class for a formal problem. A new domain subclasses this,
    overriding `actions` and `results`, and perhaps other methods.
    The default heuristic is 0 and the default action cost is 1 for all states.
    When yiou create an instance of a subclass, specify `initial`, and `goal` states
    (or give an `is_goal` method) and perhaps other keyword args for the subclass."""

    def __init__(self, initial=None, goal=None, **kwds):
        self.__dict__.update(initial=initial, goal=goal, **kwds)

    def actions(self, state):        raise NotImplementedError
    def result(self, state, action): raise NotImplementedError
    def is_goal(self, state):        return state == self.goal
    def action_cost(self, s, a, s1): return 1
    def h(self, node):               return 0

    def __str__(self):
        return '{}({!r}, {!r})'.format(
            type(self).__name__, self.initial, self.goal)

class Node:
    "A Node in a search tree."
    def __init__(self, state, parent=None, action=None, path_cost=0):
        self.__dict__.update(state=state, parent=parent, action=action, path_cost=path_cost)

    def __repr__(self): return '<{}>'.format(self.state)
    def __len__(self): return 0 if self.parent is None else (1 + len(self.parent))
    def __lt__(self, other): return self.path_cost < other.path_cost
    failure = Node('failure', path_cost=math.inf) # Indicates an algorithm couldn't find a solution.
    cutoff  = Node('cutoff',  path_cost=math.inf) # Indicates iterative deepening search was cut off.
    
    
    def expand(problem, node):
        "Expand a node, generating the children nodes."
        s = node.state
        for action in problem.actions(s):
            s1 = problem.result(s, action)
            cost = node.path_cost + problem.action_cost(s, action, s1)
            yield Node(s1, node, action, cost)
    
    
    def path_actions(node):
        "The sequence of actions to get to this node."
        if node.parent is None:
            return []
        return path_actions(node.parent) + [node.action]
    
    
    def path_states(node):
        "The sequence of states to get to this node."
        if node in (cutoff, failure, None):
            return []
        return path_states(node.parent) + [node.state]

My Grid problem is like this

class GridProblem(Problem):
    """Finding a path on a 2D grid with obstacles. Obstacles are (x, y) cells."""
    
    def __init__(self, initial=(0.5, 0.5), goal=(1.5, 2.5), obstacles=(),
                 grid_size=0.2, **kwds):
        Problem.__init__(self, initial=initial, goal=goal, obstacles=set(obstacles) - {initial, goal},
                         grid_size=grid_size, **kwds)

        
        self.directions = [(0, -1), (-1, 0), (1,  0), (0, +1)]
        self.gridmap = set()
        
        # Method for converting real map location to a grid map, there is a tricky problem 
        self.to_grid = lambda state: (int(state[0]*10/self.grid_size/10), int(state[1]*10/self.grid_size/10))
        
        self.generate_gridmap()   
    
    
    def generate_gridmap(self):
        for p in self.obstacles:
            self.gridmap.add(self.to_grid(p))
        
        # Remove initial point and goal point from grid map
        self.gridmap = self.gridmap - {self.to_grid(self.initial), self.to_grid(self.goal)}
            
                
    def result(self, state, action): 
        "Both states and actions are represented by (x, y) pairs."
        result_grid_loc = self.to_grid(state)
        return action if action not in self.gridmap else state
    
    
    def actions(self, state):
        """You can move one cell in any of `directions` to a non-obstacle cell."""
        x, y = state
        grid_p = self.to_grid(state)
        action_list = []
        for (dx, dy) in self.directions:
            next_p = (grid_p[0]+dx, grid_p[1]+dy)
            if next_p not in self.gridmap:
                action_list.append((round(next_p[0]*self.grid_size, 3), \
                                    round(next_p[1]*self.grid_size, 3)))
        return action_list
    
    
    def is_goal(self, state):
        return self.to_grid(state) == self.to_grid(self.goal)

    
    def action_cost(self, s, action, s1): return euclidean_distance(s, s1)

And just to sample, I'm using BFS and DFS as well, they go like this:

def breadth_first_search(problem):
    "Search shallowest nodes in the search tree first."
    frontier = FIFOQueue([Node(problem.initial)])
    global reached # <<<<<<<<<<< Only change here
    reached = set()
    while frontier:
        node = frontier.pop()
        if problem.is_goal(node.state):
            return node
        for child in expand(problem, node):
            s = child.state
            if s not in reached:
                reached.add(s)
                frontier.appendleft(child)
    return failure

Can somebody guide me in a direction so I can code Floyd Warshall something similar to how I did BFS?

0

There are 0 best solutions below