Artificial Intelligence-Experiment 1

first experiment

1. Experimental purpose

  • Master the algorithmic ideas of information search strategies
  • Ability to program search algorithms
  • Applying A* search algorithm to solve Romania problem

2. Algorithm principle

1. Evaluation function of A* search

Algorithm A is a heuristic algorithm. The evaluation of a node by A* search includes two parts. One part is the cost that has been spent to reach the node, recorded as g(n); the other part is the estimate of the minimum cost from the node to the target node, recorded as h. (n). Therefore, the estimated cost of the minimum cost solution passing through node n is:
f (n) = g (n) + h (n) f(n) = g(n) + h(n)f(n)=g(n)+h ( n )
​ Each time a node is expanded, the node with the smallest f(n) is expanded first. Assuming that the heuristic function h(n) satisfies certain conditions, A
search is both complete and optimal.

2. Conditions to ensure optimality

The conditions for the A* algorithm to ensure optimality are admissibility and consistency.

Admissibility means that when estimating the cost of reaching the goal, the estimated value must be smaller than the actual value, that is, f(n) must not exceed the actual cost of the solution passing through node n. Therefore, when the target node is searched, the optimal solution must be obtained, and no other node has a smaller estimated value.

​ Consistency only applies to graph searches. If for each node n and each successor node n' that generates n through any action a, the estimated cost of reaching the goal from node n is no greater than the single-step cost from n to n' and the cost of reaching the goal from n' Estimated sum of costs. This ensures that h(n) is the lower bound of reaching the target node via n.
h ( n ) ≤ c ( n , a , n ′ ) + h ( n ′ ) h(n)\leq c(n,a,n') + h(n')h(n)c(n,a,n)+h(n )
​ If h(n) is admissible, then A* for tree search is optimal; if h(n) is consistent, then A* algorithm for graph search is optimal. During the search, due to the admissibility of the A* algorithm, the expanded node has the smallest lower bound value. When the target node is expanded, the optimal solution must be obtained. Because h(n)=g(n) of the target node, and this value is less than or equal to the lower bound of any other node, and according to consistency, the cost of the target node expanded later will not be lower, so the first expanded The target node must be the optimal solution.

3. Completeness

​ Completeness requires that nodes with a cost less than or equal to C* (the cost value of the optimal solution path) are finite, the cost of each step exceeds ε and b is finite.

3. Algorithm implementation for solving the Romania problem

The Romania problem is a graph optimal path search problem that can be solved using the A* algorithm. Evaluation function f ( n ) = g ( n ) + h ( n ) f(n)=g(n)+h(n)f(n)=g(n)+h ( n ) , g(n) is the cost to reach the node, calculated when expanding node n, h(n) is the estimated cost from node n to the end point, using straight-line distance, which has been given in the question. Since the heuristic information h(n) uses straight-line distance to satisfy admissibility and consistency, this search method is optimal.

​In specific implementation, the information that each node needs to save includes g(n), h(n), and f(n)=g(n)+h(n). Since the node with the smallest f(n) needs to be taken out every time, overloading < makes it easier to sort the nodes.

struct node{
    int g;
    int h;
    int f;
    int name;
    node(int name, int g, int h){
        this->name = name;
        this->g = g;
        this->h = h;
        this->f = g + h;
    };
    bool operator <(const node &a)const{
        return f < a.f;
    }
};

Graphs are stored using adjacency matrices, and information about all edges can be initialized.

class Graph{
public:
    Graph()	{memset(graph, -1, sizeof(graph));}
    int getEdge(int from, int to)	{return graph[from][to];}
    void addEdge(int from, int to, int cost){
        if (from >= 20 || from < 0 || to >= 20 || to < 0)
            return;
        graph[from][to] = cost;
    }
	void init(){
        addEdge(O, Z, 71);
		...添加所有边
	}
private:
    int graph[20][20];
};

During the search process, the nodes to be expanded form an ordered queue. Each node is only expanded once, and the nodes that have been expanded need to be recorded. In the initial state, the g(n) value of each node is unknown, so when expanding the current node, it is necessary to update the g(n) of all nodes that the current node can reach to ensure that g(n) takes is the minimum cost to reach a node. In order to quickly determine whether the updated node is in the queue, you can directly record whether the node is in the current queue.

bool list[20];				//记录结点是否在当前队列
vector<node> openList;		//扩展队列
bool closeList[20];			//记录结点是否扩展过
stack<int> road;			//记录路径
int parent[20];				//记录路径

When starting the search, first add the starting point into the queue. As long as there are expandable nodes in the queue, it will continue to expand. When the expanded node becomes the target node, the search ends. When expanding a node, first determine whether the current node can reach the new node and whether the new node has been expanded. If the new node can be expanded and the new node is in the queue, traverse the queue to find the node and try to update g(n) and f(n). Otherwise, directly construct the new node and add it to the queue. After the current node is expanded, , sort the queue and ensure that the node with the smallest f(n) continues to be taken out for expansion.

void A_star(int goal,node &src,Graph &graph){
    openList.push_back(src);
    sort(openList.begin(), openList.end());
    while (!openList.empty()){
        /********** Begin **********/
		node cur = openList[0];
        if(cur.name==goal) return;								//取出目标结点,搜索结束
        openList.erase(openList.begin());
        closeList[cur.name] = true;								//当前结点已扩展
        list[cur.name] = false;									//当前结点出队
        for(int i=0;i<20;i++){
            if(graph.getEdge(cur.name, i)!=-1 && !closeList[i]){
                int cost = cur.g + graph.getEdge(cur.name, i);	//到达下一个城市的代价
                if(list[i]){
                   //更新已有结点
                    for(int j=0;j<openList.size();j++){
                        if(openList[j].name==i){
                            if(openList[j].g>cost){
                               openList[j].g = cost;
                               openList[j].f = openList[j].h + cost;
                               parent[i] = cur.name;
                           }
                           break;
                       }
                   }
               }
               else{
                   //构造新结点
                   node newNode(i, cost, h[i]);
                   openList.push_back(newNode);
                   list[i] = true;
                   parent[i] = cur.name;
               }
            }
        }
        sort(openList.begin(), openList.end());
		/********** End **********/  
    }
}

The search result is the optimal solution.

Insert image description here

For problems with a constant step cost, the growth of time complexity is a function of the depth d of the optimal solution, which can be analyzed by heuristic absolute errors and relative errors. The absolute error is Δ = h ∗ − h Δ=h^*-hD=hh h ∗ h^* h is the actual cost from the root node to the target node. Under the maximum absolute error, the time complexity of A* is exponentialO ( b Δ ) O(b^Δ)O(bΔ ), the cost of each step is constant, so it can be recorded asO ( b ε d ) O(b^{εd})O(bε d ), d is the depth of the solution.

4. Thinking questions

1.Which method is the best among breadth-first search, depth-first search, consistent cost search, and iteratively deepening depth-first search algorithm?

​ When the cost of each step of action is equal, breadth-first search and depth-first search with iterative deepening are optimal, otherwise the consistent search cost algorithm is optimal. The breadth-first algorithm is complete when the shallowest target is at a limited depth, but it is optimal only when the path cost is a non-decreasing function based on the node depth. The most typical one is the case where the action cost is equal, and the depth of iterative deepening Priority search is similar, and the time complexity and space complexity of the two are also the same. The consistent cost search is the optimal node, the node with the smallest expansion path consumption. Since the cost is non-negative, the first expanded target node must be the optimal solution. However, consistent cost search may explore search trees of cheap actions, which is more expensive. Depth-first search is neither complete nor optimal.

Insert image description here

2. Which method is better, greedy best first search or A* search?

The A* search algorithm is optimal. The greedy best-first algorithm does not have completeness or optimality. Whether the optimal solution is found is related to the heuristic function. The A* search algorithm is optimal when it meets admissibility and consistency, and is complete as long as the branches are limited.

3. Analyze and compare uninformation search strategies and information search strategies.

​ The information-free search strategy is a blind search, which may require greater time and space overhead to find the solution, but it has good versatility. The information-based search strategy uses the additional information of the problem through the heuristic function and advances in the direction of the possible optimal solution during the search process, which can improve the search efficiency. The performance is related to the quality of the heuristic function.

Guess you like

Origin blog.csdn.net/Aaron503/article/details/131104697