Artificial intelligence learning: python implements breadth-first search algorithm

Artificial intelligence learning: python implements breadth-first search algorithm


This article blog link:http://blog.csdn.net/jdh99 , author: jdh, reprint please specify.

 

surroundings:

Host: WIN10

Python version: 3.5

Development environment: pyCharm


Description:
Learn "A Modern Method of Artificial Intelligence" to write breadth-first algorithms.
Algorithm source code in the book:



Algorithm flow analysis:

data structure:

  • frontier: the edge. Store unexpanded nodes
  • explored : Explore the set. The state is stored (note that the previous algorithm is different)

Process:

  • If the edge is empty, it returns failure. Operation: EMPTY? (frontier)
  • Otherwise, select a leaf node from the edge. Operation: POP(frontier)
  • Put the state of the leaf node in the exploration set
  • Traverse all actions of leaf nodes
    • Each action generates child nodes
    • If the state of the child node is not in the exploration set or edge, then the target test: pass back
    • If it fails, put it on the edge. Operation: INSERT( child , frontier)

 

Note: The algorithm only puts the state of the leaf node into the exploration set before traversing all the actions of the leaf node, that is, before the width search. In the traversal process, if the child node fails the target test, the state of the child node is not put into the exploration set, but the child node is placed on the edge, and the next round of traversal based on the width of the child node is prepared.

 

 

Algorithm performance analysis:

  • complete
  • Not optimal
  • time complexity:

Assuming that each state has b successors and the depth of the solution is d, the total number of nodes:

b + b^2 + b^3 + … + b^d = O(b^d)

The above algorithm performs target detection when the node is expanded instead of when it is generated, so the time complexity should be O(b^(d+1))

  • Space complexity:

每个已扩展的节点都保存到探索集,探索集的节点数:O(b(d - 1)),边缘节点中:O(b^d)。所以控件复杂度为O(b^d),由边缘集所决定。

 




城市地图:




源码:

import pandas as pd
from pandas import Series, DataFrame

# 城市信息:city1 city2 path_cost
_city_info = None

# 按照路径消耗进行排序的FIFO,低路径消耗在前面
_frontier_priority = []


# 节点数据结构
class Node:
    def __init__(self, state, parent, action, path_cost):
        self.state = state
        self.parent = parent
        self.action = action
        self.path_cost = path_cost


def main():
    global _city_info
    import_city_info()

    while True:
        src_city = input('input src city\n')
        dst_city = input('input dst city\n')
        result = breadth_first_search(src_city, dst_city)
        if not result:
            print('from city: %s to city %s search failure' % (src_city, dst_city))
        else:
            print('from city: %s to city %s search success' % (src_city, dst_city))
            path = []
            while True:
                path.append(result.state)
                if result.parent is None:
                    break
                result = result.parent
            size = len(path)
            for i in range(size):
                if i < size - 1:
                    print('%s->' % path.pop(), end='')
                else:
                    print(path.pop())


def import_city_info():
    global _city_info
    data = [{'city1': 'Oradea', 'city2': 'Zerind', 'path_cost': 71},
            {'city1': 'Oradea', 'city2': 'Sibiu', 'path_cost': 151},
            {'city1': 'Zerind', 'city2': 'Arad', 'path_cost': 75},
            {'city1': 'Arad', 'city2': 'Sibiu', 'path_cost': 140},
            {'city1': 'Arad', 'city2': 'Timisoara', 'path_cost': 118},
            {'city1': 'Timisoara', 'city2': 'Lugoj', 'path_cost': 111},
            {'city1': 'Lugoj', 'city2': 'Mehadia', 'path_cost': 70},
            {'city1': 'Mehadia', 'city2': 'Drobeta', 'path_cost': 75},
            {'city1': 'Drobeta', 'city2': 'Craiova', 'path_cost': 120},
            {'city1': 'Sibiu', 'city2': 'Fagaras', 'path_cost': 99},
            {'city1': 'Sibiu', 'city2': 'Rimnicu Vilcea', 'path_cost': 80},
            {'city1': 'Rimnicu Vilcea', 'city2': 'Craiova', 'path_cost': 146},
            {'city1': 'Rimnicu Vilcea', 'city2': 'Pitesti', 'path_cost': 97},
            {'city1': 'Craiova', 'city2': 'Pitesti', 'path_cost': 138},
            {'city1': 'Fagaras', 'city2': 'Bucharest', 'path_cost': 211},
            {'city1': 'Pitesti', 'city2': 'Bucharest', 'path_cost': 101},
            {'city1': 'Bucharest', 'city2': 'Giurgiu', 'path_cost': 90},
            {'city1': 'Bucharest', 'city2': 'Urziceni', 'path_cost': 85},
            {'city1': 'Urziceni', 'city2': 'Vaslui', 'path_cost': 142},
            {'city1': 'Urziceni', 'city2': 'Hirsova', 'path_cost': 98},
            {'city1': 'Neamt', 'city2': 'Iasi', 'path_cost': 87},
            {'city1': 'Iasi', 'city2': 'Vaslui', 'path_cost': 92},
            {'city1': 'Hirsova', 'city2': 'Eforie', 'path_cost': 86}]

    _city_info = DataFrame(data, columns=['city1', 'city2', 'path_cost'])
    # print(_city_info)


def breadth_first_search(src_state, dst_state):
    global _city_info

    node = Node(src_state, None, None, 0)
    # 目标测试
    if node.state == dst_state:
        return node
    frontier = [node]
    explored = []

    while True:
        if len(frontier) == 0:
            return False
        node = frontier.pop(0)
        explored.append(node.state)
        if node.parent is not None:
            print('deal node:state:%s\tparent state:%s\tpath cost:%d' % (node.state, node.parent.state, node.path_cost))
        else:
            print('deal node:state:%s\tparent state:%s\tpath cost:%d' % (node.state, None, node.path_cost))

        # 遍历子节点
        for i in range(len(_city_info)):
            dst_city = ''
            if _city_info['city1'][i] == node.state:
                dst_city = _city_info['city2'][i]
            elif _city_info['city2'][i] == node.state:
                dst_city = _city_info['city1'][i]
            if dst_city == '':
                continue
            child = Node(dst_city, node, 'go', node.path_cost + _city_info['path_cost'][i])
            print('\tchild node:state:%s path cost:%d' % (child.state, child.path_cost))
            if child.state not in explored and not is_node_in_frontier(frontier, child):
                # 目标测试
                if child.state == dst_state:
                    print('\t\t this child is goal!')
                    return child
                frontier.append(child)
                print('\t\t add child to child')


def is_node_in_frontier(frontier, node):
    for x in frontier:
        if node.state == x.state:
            return True
    return False


if __name__ == '__main__':
    main()




 
     
 
     
利用算法求解:
input src city
Zerind
input dst city
Urziceni
deal node:state:Zerind parent state:None path cost:0
 child node:state:Oradea path cost:71
   add child to child
 child node:state:Arad path cost:75
   add child to child
deal node:state:Oradea parent state:Zerind path cost:71
 child node:state:Zerind path cost:142
 child node:state:Sibiu path cost:222
   add child to child
deal node:state:Arad parent state:Zerind path cost:75
 child node:state:Zerind path cost:150
 child node:state:Sibiu path cost:215
 child node:state:Timisoara path cost:193
   add child to child
deal node:state:Sibiu parent state:Oradea path cost:222
 child node:state:Oradea path cost:373
 child node:state:Arad path cost:362
 child node:state:Fagaras path cost:321
   add child to child
 child node:state:Rimnicu Vilcea path cost:302
   add child to child
deal node:state:Timisoara parent state:Arad path cost:193
 child node:state:Arad path cost:311
 child node:state:Lugoj path cost:304
   add child to child
deal node:state:Fagaras parent state:Sibiu path cost:321
 child node:state:Sibiu path cost:420
 child node:state:Bucharest path cost:532
   add child to child
deal node:state:Rimnicu Vilcea parent state:Sibiu path cost:302
 child node:state:Sibiu path cost:382
 child node:state:Craiova path cost:448
   add child to child
 child node:state:Pitesti path cost:399
   add child to child
deal node:state:Lugoj parent state:Timisoara path cost:304
 child node:state:Timisoara path cost:415
 child node:state:Mehadia path cost:374
   add child to child
deal node:state:Bucharest parent state:Fagaras path cost:532
 child node:state:Fagaras path cost:743
 child node:state:Pitesti path cost:633
 child node:state:Giurgiu path cost:622
   add child to child
 child node:state:Urziceni path cost:617
   this child is goal!
from city: Zerind to city Urziceni search success
Zerind->Oradea->Sibiu->Fagaras->Bucharest->Urziceni

The optimal path from Zerind to Urziceni should be Zerind->Arad->Sibiu->Rimnicu Vilcea->Pitesti->Bucharest->Urziceni, so this algorithm is not an optimal algorithm, but just a solution.


bibliography:

1. "A Modern Method of Artificial Intelligence"





Guess you like

Origin blog.csdn.net/jdh99/article/details/80851261