Skip to content

Commit 09beeb4

Browse files
Chipe1norvig
authored andcommitted
Added tests (aimacode#620)
* Added tests for search.py * Updated readme * Removed extra newline * Fixed seed * Update README.md * Added docstring for minimal-consistent-det
1 parent 6e12df4 commit 09beeb4

File tree

5 files changed

+103
-9
lines changed

5 files changed

+103
-9
lines changed

README.md

+8-8
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ Here is a table of algorithms, the figure, name of the algorithm in the book and
4646
| 3.14 | Uniform-Cost-Search | `uniform_cost_search` | [`search.py`][search] | Done |
4747
| 3.17 | Depth-Limited-Search | `depth_limited_search` | [`search.py`][search] | Done |
4848
| 3.18 | Iterative-Deepening-Search | `iterative_deepening_search` | [`search.py`][search] | Done |
49-
| 3.22 | Best-First-Search | `best_first_graph_search` | [`search.py`][search] | |
49+
| 3.22 | Best-First-Search | `best_first_graph_search` | [`search.py`][search] | Done |
5050
| 3.24 | A\*-Search | `astar_search` | [`search.py`][search] | Done |
5151
| 3.26 | Recursive-Best-First-Search | `recursive_best_first_search` | [`search.py`][search] | Done |
52-
| 4.2 | Hill-Climbing | `hill_climbing` | [`search.py`][search] | |
53-
| 4.5 | Simulated-Annealing | `simulated_annealing` | [`search.py`][search] | |
52+
| 4.2 | Hill-Climbing | `hill_climbing` | [`search.py`][search] | Done |
53+
| 4.5 | Simulated-Annealing | `simulated_annealing` | [`search.py`][search] | Done |
5454
| 4.8 | Genetic-Algorithm | `genetic_algorithm` | [`search.py`][search] | Done |
5555
| 4.11 | And-Or-Graph-Search | `and_or_graph_search` | [`search.py`][search] | Done |
5656
| 4.21 | Online-DFS-Agent | `online_dfs_agent` | [`search.py`][search] | |
@@ -60,7 +60,7 @@ Here is a table of algorithms, the figure, name of the algorithm in the book and
6060
| 6 | CSP | `CSP` | [`csp.py`][csp] | Done |
6161
| 6.3 | AC-3 | `AC3` | [`csp.py`][csp] | Done |
6262
| 6.5 | Backtracking-Search | `backtracking_search` | [`csp.py`][csp] | Done |
63-
| 6.8 | Min-Conflicts | `min_conflicts` | [`csp.py`][csp] | |
63+
| 6.8 | Min-Conflicts | `min_conflicts` | [`csp.py`][csp] | Done |
6464
| 6.11 | Tree-CSP-Solver | `tree_csp_solver` | [`csp.py`][csp] | Done |
6565
| 7 | KB | `KB` | [`logic.py`][logic] | Done |
6666
| 7.1 | KB-Agent | `KB_Agent` | [`logic.py`][logic] | Done |
@@ -71,7 +71,7 @@ Here is a table of algorithms, the figure, name of the algorithm in the book and
7171
| 7.15 | PL-FC-Entails? | `pl_fc_resolution` | [`logic.py`][logic] | Done |
7272
| 7.17 | DPLL-Satisfiable? | `dpll_satisfiable` | [`logic.py`][logic] | Done |
7373
| 7.18 | WalkSAT | `WalkSAT` | [`logic.py`][logic] | Done |
74-
| 7.20 | Hybrid-Wumpus-Agent | `HybridWumpusAgent` | [`logic.py`][logic]\* | |
74+
| 7.20 | Hybrid-Wumpus-Agent | `HybridWumpusAgent` | | |
7575
| 7.22 | SATPlan | `SAT_plan` | [`logic.py`][logic] | Done |
7676
| 9 | Subst | `subst` | [`logic.py`][logic] | Done |
7777
| 9.1 | Unify | `unify` | [`logic.py`][logic] | Done |
@@ -102,21 +102,21 @@ Here is a table of algorithms, the figure, name of the algorithm in the book and
102102
| 16.9 | Information-Gathering-Agent | | |
103103
| 17.4 | Value-Iteration | `value_iteration` | [`mdp.py`][mdp] | Done |
104104
| 17.7 | Policy-Iteration | `policy_iteration` | [`mdp.py`][mdp] | Done |
105-
| 17.7 | POMDP-Value-Iteration | | | |
105+
| 17.9 | POMDP-Value-Iteration | | | |
106106
| 18.5 | Decision-Tree-Learning | `DecisionTreeLearner` | [`learning.py`][learning] | Done |
107107
| 18.8 | Cross-Validation | `cross_validation` | [`learning.py`][learning] | |
108108
| 18.11 | Decision-List-Learning | `DecisionListLearner` | [`learning.py`][learning]\* | |
109109
| 18.24 | Back-Prop-Learning | `BackPropagationLearner` | [`learning.py`][learning] | Done |
110110
| 18.34 | AdaBoost | `AdaBoost` | [`learning.py`][learning] | |
111111
| 19.2 | Current-Best-Learning | `current_best_learning` | [`knowledge.py`](knowledge.py) | Done |
112112
| 19.3 | Version-Space-Learning | `version_space_learning` | [`knowledge.py`](knowledge.py) | Done |
113-
| 19.8 | Minimal-Consistent-Det | | |
113+
| 19.8 | Minimal-Consistent-Det | `minimal_consistent_det` | [`knowledge.py`](knowledge.py) | Done |
114114
| 19.12 | FOIL | | |
115115
| 21.2 | Passive-ADP-Agent | `PassiveADPAgent` | [`rl.py`][rl] | Done |
116116
| 21.4 | Passive-TD-Agent | `PassiveTDAgent` | [`rl.py`][rl] | Done |
117117
| 21.8 | Q-Learning-Agent | `QLearningAgent` | [`rl.py`][rl] | Done |
118118
| 22.1 | HITS | `HITS` | [`nlp.py`][nlp] | Done |
119-
| 23 | Chart-Parse | `Chart` | [`nlp.py`][nlp] | |
119+
| 23 | Chart-Parse | `Chart` | [`nlp.py`][nlp] | Done |
120120
| 23.5 | CYK-Parse | `CYK_parse` | [`nlp.py`][nlp] | Done |
121121
| 25.9 | Monte-Carlo-Localization| `monte_carlo_localization` | [`probability.py`][probability] | Done |
122122

knowledge.py

+2
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ def build_h_combinations(hypotheses):
207207

208208

209209
def minimal_consistent_det(E, A):
210+
"""Returns a minimal set of attributes which give consistent determination"""
210211
n = len(A)
211212

212213
for i in range(n + 1):
@@ -216,6 +217,7 @@ def minimal_consistent_det(E, A):
216217

217218

218219
def consistent_det(A, E):
220+
"""Checks if the attributes(A) is consistent with the examples(E)"""
219221
H = {}
220222

221223
for e in E:

search.py

+41
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,47 @@ def and_search(states, problem, path):
509509
return or_search(problem.initial, problem, [])
510510

511511

512+
class PeakFindingProblem(Problem):
513+
"""Problem of finding the highest peak in a limited grid"""
514+
515+
def __init__(self, initial, grid):
516+
"""The grid is a 2 dimensional array/list whose state is specified by tuple of indices"""
517+
Problem.__init__(self, initial)
518+
self.grid = grid
519+
self.n = len(grid)
520+
assert self.n > 0
521+
self.m = len(grid[0])
522+
assert self.m > 0
523+
524+
def actions(self, state):
525+
"""Allows movement in only 4 directions"""
526+
# TODO: Add flag to allow diagonal motion
527+
allowed_actions = []
528+
if state[0] > 0:
529+
allowed_actions.append('N')
530+
if state[0] < self.n - 1:
531+
allowed_actions.append('S')
532+
if state[1] > 0:
533+
allowed_actions.append('W')
534+
if state[1] < self.m - 1:
535+
allowed_actions.append('E')
536+
return allowed_actions
537+
538+
def result(self, state, action):
539+
"""Moves in the direction specified by action"""
540+
x, y = state
541+
x = x + (1 if action == 'S' else (-1 if action == 'N' else 0))
542+
y = y + (1 if action == 'E' else (-1 if action == 'W' else 0))
543+
return (x, y)
544+
545+
def value(self, state):
546+
"""Value of a state is the value it is the index to"""
547+
x, y = state
548+
assert 0 <= x < self.n
549+
assert 0 <= y < self.m
550+
return self.grid[x][y]
551+
552+
512553
class OnlineDFSAgent:
513554

514555
"""[Figure 4.21] The abstract class for an OnlineDFSAgent. Override

tests/test_csp.py

+9
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,15 @@ def test_backtracking_search():
330330
order_domain_values=lcv, inference=mac)
331331

332332

333+
def test_min_conflicts():
334+
random.seed("aima-python")
335+
assert min_conflicts(australia)
336+
assert min_conflicts(usa)
337+
assert min_conflicts(france)
338+
australia_impossible = MapColoringCSP(list('RG'), 'SA: WA NT Q NSW V; NT: WA Q; NSW: Q V; T: ')
339+
assert min_conflicts(australia_impossible, 1000) is None
340+
341+
333342
def test_universal_dict():
334343
d = UniversalDict(42)
335344
assert d['life'] == 42

tests/test_search.py

+43-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
vacumm_world = GraphProblemStochastic('State_1', ['State_7', 'State_8'], vacumm_world)
77
LRTA_problem = OnlineSearchProblem('State_3', 'State_5', one_dim_state_space)
88

9-
109
def test_find_min_edge():
1110
assert romania_problem.find_min_edge() == 70
1211

@@ -20,6 +19,22 @@ def test_breadth_first_search():
2019
assert breadth_first_search(romania_problem).solution() == ['Sibiu', 'Fagaras', 'Bucharest']
2120

2221

22+
def test_best_first_graph_search():
23+
# uniform_cost_search and astar_search test it indirectly
24+
assert best_first_graph_search(
25+
romania_problem,
26+
lambda node: node.state).solution() == ['Sibiu', 'Fagaras', 'Bucharest']
27+
assert best_first_graph_search(
28+
romania_problem,
29+
lambda node: node.state[::-1]).solution() == ['Timisoara',
30+
'Lugoj',
31+
'Mehadia',
32+
'Drobeta',
33+
'Craiova',
34+
'Pitesti',
35+
'Bucharest']
36+
37+
2338
def test_uniform_cost_search():
2439
assert uniform_cost_search(
2540
romania_problem).solution() == ['Sibiu', 'Rimnicu', 'Pitesti', 'Bucharest']
@@ -56,6 +71,33 @@ def test_recursive_best_first_search():
5671
romania_problem).solution() == ['Sibiu', 'Rimnicu', 'Pitesti', 'Bucharest']
5772

5873

74+
def test_hill_climbing():
75+
prob = PeakFindingProblem((0, 0), [[0, 5, 10, 20],
76+
[-3, 7, 11, 5]])
77+
assert hill_climbing(prob) == (0, 3)
78+
prob = PeakFindingProblem((0, 0), [[0, 5, 10, 8],
79+
[-3, 7, 9, 999],
80+
[1, 2, 5, 11]])
81+
assert hill_climbing(prob) == (0, 2)
82+
prob = PeakFindingProblem((2, 0), [[0, 5, 10, 8],
83+
[-3, 7, 9, 999],
84+
[1, 2, 5, 11]])
85+
assert hill_climbing(prob) == (1, 3)
86+
87+
88+
def test_simulated_annealing():
89+
random.seed("aima-python")
90+
prob = PeakFindingProblem((0, 0), [[0, 5, 10, 20],
91+
[-3, 7, 11, 5]])
92+
sols = {prob.value(simulated_annealing(prob)) for i in range(100)}
93+
assert max(sols) == 20
94+
prob = PeakFindingProblem((0, 0), [[0, 5, 10, 8],
95+
[-3, 7, 9, 999],
96+
[1, 2, 5, 11]])
97+
sols = {prob.value(simulated_annealing(prob)) for i in range(100)}
98+
assert max(sols) == 999
99+
100+
59101
def test_BoggleFinder():
60102
board = list('SARTELNID')
61103
"""

0 commit comments

Comments
 (0)