Skip to content

Commit 48bd2f7

Browse files
ad71norvig
authored andcommitted
Search notebook update (aimacode#933)
* Added tests for online dfs agent * Minor formatting fixes * Completed notebook sections * Updated README.md * Fixed a test * Added new algorithms to display_visual notebook function * Added RBFS visualization
1 parent 0c222e1 commit 48bd2f7

File tree

5 files changed

+3265
-2028
lines changed

5 files changed

+3265
-2028
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,13 +78,13 @@ Here is a table of algorithms, the figure, name of the algorithm in the book and
7878
| 3.18 | Iterative-Deepening-Search | `iterative_deepening_search` | [`search.py`][search] | Done | Included |
7979
| 3.22 | Best-First-Search | `best_first_graph_search` | [`search.py`][search] | Done | Included |
8080
| 3.24 | A\*-Search | `astar_search` | [`search.py`][search] | Done | Included |
81-
| 3.26 | Recursive-Best-First-Search | `recursive_best_first_search` | [`search.py`][search] | Done | |
81+
| 3.26 | Recursive-Best-First-Search | `recursive_best_first_search` | [`search.py`][search] | Done | Included |
8282
| 4.2 | Hill-Climbing | `hill_climbing` | [`search.py`][search] | Done | Included |
8383
| 4.5 | Simulated-Annealing | `simulated_annealing` | [`search.py`][search] | Done | Included |
8484
| 4.8 | Genetic-Algorithm | `genetic_algorithm` | [`search.py`][search] | Done | Included |
85-
| 4.11 | And-Or-Graph-Search | `and_or_graph_search` | [`search.py`][search] | Done | |
86-
| 4.21 | Online-DFS-Agent | `online_dfs_agent` | [`search.py`][search] | | |
87-
| 4.24 | LRTA\*-Agent | `LRTAStarAgent` | [`search.py`][search] | Done | |
85+
| 4.11 | And-Or-Graph-Search | `and_or_graph_search` | [`search.py`][search] | Done | Included |
86+
| 4.21 | Online-DFS-Agent | `online_dfs_agent` | [`search.py`][search] | Done | Included |
87+
| 4.24 | LRTA\*-Agent | `LRTAStarAgent` | [`search.py`][search] | Done | Included |
8888
| 5.3 | Minimax-Decision | `minimax_decision` | [`games.py`][games] | Done | Included |
8989
| 5.7 | Alpha-Beta-Search | `alphabeta_search` | [`games.py`][games] | Done | Included |
9090
| 6 | CSP | `CSP` | [`csp.py`][csp] | Done | Included |

notebook.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -992,8 +992,13 @@ def visualize_callback(Visualize):
992992
"Depth First Tree Search",
993993
"Breadth First Search",
994994
"Depth First Graph Search",
995+
"Best First Graph Search",
995996
"Uniform Cost Search",
996-
"A-star Search"})
997+
"Depth Limited Search",
998+
"Iterative Deepening Search",
999+
"Greedy Best First Search",
1000+
"A-star Search",
1001+
"Recursive Best First Search"})
9971002

9981003
algo_dropdown = widgets.Dropdown(description="Search algorithm: ",
9991004
options=sorted(list(algorithm.keys())),

search.ipynb

Lines changed: 3200 additions & 2003 deletions
Large diffs are not rendered by default.

search.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -767,8 +767,8 @@ def __init__(self, problem):
767767
self.problem = problem
768768
self.s = None
769769
self.a = None
770-
self.untried = defaultdict(list)
771-
self.unbacktracked = defaultdict(list)
770+
self.untried = dict()
771+
self.unbacktracked = dict()
772772
self.result = {}
773773

774774
def __call__(self, percept):
@@ -787,13 +787,13 @@ def __call__(self, percept):
787787
self.a = None
788788
else:
789789
# else a <- an action b such that result[s', b] = POP(unbacktracked[s'])
790-
unbacktracked_pop = self.unbacktracked[s1].pop(0)
790+
unbacktracked_pop = self.unbacktracked.pop(s1)
791791
for (s, b) in self.result.keys():
792792
if self.result[(s, b)] == unbacktracked_pop:
793793
self.a = b
794794
break
795795
else:
796-
self.a = self.untried[s1].pop(0)
796+
self.a = self.untried.pop(s1)
797797
self.s = s1
798798
return self.a
799799

@@ -1120,7 +1120,7 @@ def distance_to_node(n):
11201120
7 - CCL Clean Clean Left
11211121
8 - CCR Clean Clean Right
11221122
"""
1123-
vacumm_world = Graph(dict(
1123+
vacuum_world = Graph(dict(
11241124
State_1=dict(Suck=['State_7', 'State_5'], Right=['State_2']),
11251125
State_2=dict(Suck=['State_8', 'State_4'], Left=['State_2']),
11261126
State_3=dict(Suck=['State_7'], Right=['State_4']),

tests/test_search.py

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33

44

55
romania_problem = GraphProblem('Arad', 'Bucharest', romania_map)
6-
vacumm_world = GraphProblemStochastic('State_1', ['State_7', 'State_8'], vacumm_world)
6+
vacuum_world = GraphProblemStochastic('State_1', ['State_7', 'State_8'], vacuum_world)
77
LRTA_problem = OnlineSearchProblem('State_3', 'State_5', one_dim_state_space)
88
eight_puzzle = EightPuzzle((1, 2, 3, 4, 5, 7, 8, 6, 0))
99
eight_puzzle2 = EightPuzzle((1, 0, 6, 8, 7, 5, 4, 2), (0, 1, 2, 3, 4, 5, 6, 7, 8))
1010
nqueens = NQueensProblem(8)
1111

12+
1213
def test_find_min_edge():
1314
assert romania_problem.find_min_edge() == 70
1415

@@ -151,7 +152,33 @@ def test_conflict():
151152
def test_recursive_best_first_search():
152153
assert recursive_best_first_search(
153154
romania_problem).solution() == ['Sibiu', 'Rimnicu', 'Pitesti', 'Bucharest']
155+
assert recursive_best_first_search(
156+
EightPuzzle((2, 4, 3, 1, 5, 6, 7, 8, 0))).solution() == [
157+
'UP', 'LEFT', 'UP', 'LEFT', 'DOWN', 'RIGHT', 'RIGHT', 'DOWN'
158+
]
159+
160+
def manhattan(node):
161+
state = node.state
162+
index_goal = {0:[2,2], 1:[0,0], 2:[0,1], 3:[0,2], 4:[1,0], 5:[1,1], 6:[1,2], 7:[2,0], 8:[2,1]}
163+
index_state = {}
164+
index = [[0,0], [0,1], [0,2], [1,0], [1,1], [1,2], [2,0], [2,1], [2,2]]
165+
x, y = 0, 0
166+
167+
for i in range(len(state)):
168+
index_state[state[i]] = index[i]
169+
170+
mhd = 0
171+
172+
for i in range(8):
173+
for j in range(2):
174+
mhd = abs(index_goal[i][j] - index_state[i][j]) + mhd
175+
176+
return mhd
154177

178+
assert recursive_best_first_search(
179+
EightPuzzle((2, 4, 3, 1, 5, 6, 7, 8, 0)), h=manhattan).solution() == [
180+
'LEFT', 'UP', 'UP', 'LEFT', 'DOWN', 'RIGHT', 'DOWN', 'UP', 'DOWN', 'RIGHT'
181+
]
155182

156183
def test_hill_climbing():
157184
prob = PeakFindingProblem((0, 0), [[0, 5, 10, 20],
@@ -200,23 +227,31 @@ def run_plan(state, problem, plan):
200227
return False
201228
predicate = lambda x: run_plan(x, problem, plan[1][x])
202229
return all(predicate(r) for r in problem.result(state, plan[0]))
203-
plan = and_or_graph_search(vacumm_world)
204-
assert run_plan('State_1', vacumm_world, plan)
230+
plan = and_or_graph_search(vacuum_world)
231+
assert run_plan('State_1', vacuum_world, plan)
232+
233+
234+
def test_online_dfs_agent():
235+
odfs_agent = OnlineDFSAgent(LRTA_problem)
236+
keys = [key for key in odfs_agent('State_3')]
237+
assert keys[0] in ['Right', 'Left']
238+
assert keys[1] in ['Right', 'Left']
239+
assert odfs_agent('State_5') is None
205240

206241

207242
def test_LRTAStarAgent():
208-
my_agent = LRTAStarAgent(LRTA_problem)
209-
assert my_agent('State_3') == 'Right'
210-
assert my_agent('State_4') == 'Left'
211-
assert my_agent('State_3') == 'Right'
212-
assert my_agent('State_4') == 'Right'
213-
assert my_agent('State_5') is None
214-
215-
my_agent = LRTAStarAgent(LRTA_problem)
216-
assert my_agent('State_4') == 'Left'
217-
218-
my_agent = LRTAStarAgent(LRTA_problem)
219-
assert my_agent('State_5') is None
243+
lrta_agent = LRTAStarAgent(LRTA_problem)
244+
assert lrta_agent('State_3') == 'Right'
245+
assert lrta_agent('State_4') == 'Left'
246+
assert lrta_agent('State_3') == 'Right'
247+
assert lrta_agent('State_4') == 'Right'
248+
assert lrta_agent('State_5') is None
249+
250+
lrta_agent = LRTAStarAgent(LRTA_problem)
251+
assert lrta_agent('State_4') == 'Left'
252+
253+
lrta_agent = LRTAStarAgent(LRTA_problem)
254+
assert lrta_agent('State_5') is None
220255

221256

222257
def test_genetic_algorithm():

0 commit comments

Comments
 (0)