diff --git a/machine_learning/astar.py b/machine_learning/astar.py new file mode 100644 index 000000000000..2dd10b1d5fa7 --- /dev/null +++ b/machine_learning/astar.py @@ -0,0 +1,152 @@ +import numpy as np + +''' +The A* algorithm combines features of uniform-cost search and pure +heuristic search to efficiently compute optimal solutions. +A* algorithm is a best-first search algorithm in which the cost +associated with a node is f(n) = g(n) + h(n), +where g(n) is the cost of the path from the initial state to node n and +h(n) is the heuristic estimate or the cost or a path +from node n to a goal.A* algorithm introduces a heuristic into a +regular graph-searching algorithm, +essentially planning ahead at each step so a more optimal decision +is made.A* also known as the algorithm with brains +''' + + +class Cell(object): + ''' + Class cell represents a cell in the world which have the property + position : The position of the represented by tupleof x and y + co-ordinates initially set to (0,0) + parent : This contains the parent cell object which we visited + before arrinving this cell + g,h,f : The parameters for constructing the heuristic function + which can be any function. for simplicity used line + distance + ''' + def __init__(self): + self.position = (0, 0) + self.parent = None + + self.g = 0 + self.h = 0 + self.f = 0 + ''' + overrides equals method because otherwise cell assign will give + wrong results + ''' + def __eq__(self, cell): + return self.position == cell.position + + def showcell(self): + print(self.position) + + +class Gridworld(object): + + ''' + Gridworld class represents the external world here a grid M*M + matrix + w : create a numpy array with the given world_size default is 5 + ''' + + def __init__(self, world_size=(5, 5)): + self.w = np.zeros(world_size) + self.world_x_limit = world_size[0] + self.world_y_limit = world_size[1] + + def show(self): + print(self.w) + + ''' + get_neighbours + As the name suggests this function will return the neighbours of + the a particular cell + ''' + def get_neigbours(self, cell): + neughbour_cord = [ + (-1, -1), (-1, 0), (-1, 1), (0, -1), + (0, 1), (1, -1), (1, 0), (1, 1)] + current_x = cell.position[0] + current_y = cell.position[1] + neighbours = [] + for n in neughbour_cord: + x = current_x + n[0] + y = current_y + n[1] + if ( + (x >= 0 and x < self.world_x_limit) and + (y >= 0 and y < self.world_y_limit)): + c = Cell() + c.position = (x, y) + c.parent = cell + neighbours.append(c) + return neighbours + +''' +Implementation of a start algorithm +world : Object of the world object +start : Object of the cell as start position +stop : Object of the cell as goal position +''' + + +def astar(world, start, goal): + ''' + >>> p = Gridworld() + >>> start = Cell() + >>> start.position = (0,0) + >>> goal = Cell() + >>> goal.position = (4,4) + >>> astar(p, start, goal) + [(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)] + ''' + _open = [] + _closed = [] + _open.append(start) + + while _open: + min_f = np.argmin([n.f for n in _open]) + current = _open[min_f] + _closed.append(_open.pop(min_f)) + if current == goal: + break + for n in world.get_neigbours(current): + for c in _closed: + if c == n: + continue + n.g = current.g + 1 + x1, y1 = n.position + x2, y2 = goal.position + n.h = (y2 - y1)**2 + (x2 - x1)**2 + n.f = n.h + n.g + + for c in _open: + if c == n and c.f < n.f: + continue + _open.append(n) + path = [] + while current.parent is not None: + path.append(current.position) + current = current.parent + path.append(current.position) + path = path[::-1] + return path + +if __name__ == '__main__': + ''' + sample run + ''' +# object for the world + p = Gridworld() +# stat position and Goal + start = Cell() + start.position = (0, 0) + goal = Cell() + goal.position = (4, 4) + print("path from {} to {} ".format(start.position, goal.position)) + s = astar(p, start, goal) +# Just for visual Purpose + for i in s: + p.w[i] = 1 + print(p.w)