def hill_climbing(problem):\n",
- " """From the initial node, keep choosing the neighbor with highest value,\n",
- " stopping when no neighbor is better. [Figure 4.2]"""\n",
- " current = Node(problem.initial)\n",
- " while True:\n",
- " neighbors = current.expand(problem)\n",
- " if not neighbors:\n",
- " break\n",
- " neighbor = argmax_random_tie(neighbors,\n",
- " key=lambda node: problem.value(node.state))\n",
- " if problem.value(neighbor.state) <= problem.value(current.state):\n",
- " break\n",
- " current = neighbor\n",
- " return current.state\n",
+ "def recursive_best_first_search(problem, h=None):\n",
+ " """[Figure 3.26] Recursive best-first search (RBFS) is an\n",
+ " informative search algorithm. Like A*, it uses the heuristic\n",
+ " f(n) = g(n) + h(n) to determine the next node to expand, making\n",
+ " it both optimal and complete (iff the heuristic is consistent).\n",
+ " To reduce memory consumption, RBFS uses a depth first search\n",
+ " and only retains the best f values of its ancestors."""\n",
+ " h = memoize(h or problem.h, 'h')\n",
+ "\n",
+ " def RBFS(problem, node, flimit):\n",
+ " if problem.goal_test(node.state):\n",
+ " return node, 0 # (The second value is immaterial)\n",
+ " successors = node.expand(problem)\n",
+ " if len(successors) == 0:\n",
+ " return None, infinity\n",
+ " for s in successors:\n",
+ " s.f = max(s.path_cost + h(s), node.f)\n",
+ " while True:\n",
+ " # Order by lowest f value\n",
+ " successors.sort(key=lambda x: x.f)\n",
+ " best = successors[0]\n",
+ " if best.f > flimit:\n",
+ " return None, best.f\n",
+ " if len(successors) > 1:\n",
+ " alternative = successors[1].f\n",
+ " else:\n",
+ " alternative = infinity\n",
+ " result, best.f = RBFS(problem, best, min(flimit, alternative))\n",
+ " if result is not None:\n",
+ " return result, best.f\n",
+ "\n",
+ " node = Node(problem.initial)\n",
+ " node.f = h(node)\n",
+ " result, bestf = RBFS(problem, node, infinity)\n",
+ " return result\n",
" \n",
"\n",
"