0

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?

ravenspoint
  • 19,093
  • 6
  • 57
  • 103
  • 2
    "Now the algorithm does work with graphs, but with grids I'm not very sure." A grid is just a graph where each square is a node, and the edges connect adjacent squares. What's the difficulty? – Karl Knechtel Sep 27 '21 at 02:06
  • The usual motivation for implementing Floyd–Warshall is the presence of negative weights. It does not look like you have -ve weights in your problem. So shy not stick to BFS or DFS - they are simpler and easier to use. You might also want to look at A* which is often used for this exact problem. – ravenspoint Sep 27 '21 at 13:24
  • @KarlKnechtel I do understand that, but from what I'm reading Floyd Warshall works on a directed graph, in a grid my player has the option for 4 directions (up, down, left or right), pardon me if I still don't understand the logic but in the code I have to expand a node to get its children and do the same to them to get to the goal. BFS, DFS & Dijsktra work flawlessy, but I can't figure out a similar algorithm for Floyd Warshall that it would fit my class definitions... – Pascal Zurich Sep 27 '21 at 14:50
  • @ravenspoint They definitely are! I even implemented Dijkstra, but guess our professor wants to see all the algorithms, no matter their inefficiency. I am looking to code it similar to how I did BFS, DFS & Dijkstra they all fit the problem definition by AIMA perfectly. – Pascal Zurich Sep 27 '21 at 14:52
  • "but from what I'm reading Floyd Warshall works on a directed graph, in a grid my player has the option for 4 directions (up, down, left or right)" Okay, so for a given location (node) in the grid, you know which directions you can go, and therefore which other nodes you can reach, and therefore what edges you have from that node. A bidirectional graph is just a directed graph where each edge is doubled up (forward and reverse). Again, what's the problem? – Karl Knechtel Sep 27 '21 at 19:37
  • @KarlKnechtel I guess I just can't visualize it, again I'm just starting out, so maybe I'm having troubles designing it to fit the AIMA problem definition... oh well back to the drawing board. P.S The thing I'm having trouble wrapping my head around is, that Floyd Warshall needs a starting matrix initialized with all the node pairs (correct me if im wrong), I do not have all the nodes rather iteratively 'expand' each node to find its neighbours, secondly it needs a path cost on each of these node pairs, which again is counter intuitive as I'm trying to find the cost anyway.. – Pascal Zurich Sep 28 '21 at 02:22
  • So problem is, I don't have an adjacency matrix, as I don't know the nodes, I don't have path costs from one node to another, I only have path cost from initial node to another node... – Pascal Zurich Sep 28 '21 at 02:27

0 Answers0