写了两年c了 终于迈出了自己写python的第一步...过程极为折磨...好在最后写出来报告也交了....
直接上可运行代码 有问题可以直接私聊我
nQueens.py:
import random
from pprint import pprint
import time
def input_size_board():
''' Take input from user for size of board '''
n = input("Enter an integer for the size of the board: ")
return int(n)
def print_board(board, n):
''' Helper function for printing board '''
print('分布:')
for i in range(len(board)):
print(str(board[i]) + ' ', end='')
if (i + 1) % n == 0:
print()
print('冲突次数: ', determine_h_cost(board, n))
print('---------------------')
def generate_random_board(n):
''' Generates a random board for initialization, queens have been calculated row-wise '''
generated_board = []
for i in range(n):
j = random.randint(0, n - 1)
row = [0] * n
row[j] = 1
generated_board.extend(row)
return generated_board
def find_collisions(board, n):
''' Helper function for calculating queen position collisions '''
collisions = 0
occurences = []
max_index = len(board)
for i in range(max_index):
# For each queen on the board, count collisions with other queens, and which kind of collisions they are
if board[i] == 1:
for x in range(1, n):
# checking above current index
if (i - n * x >= 0):
north = i - n * x
# direction north
if (board[north] == 1):
collisions += 1
occurences.append('north: ' + str(i) + ' and ' + str(north))
# direction northwest
if (int((north - x) / n) == int(north / n)) and (north - x) >= 0:
northwest = north - x
if (board[northwest] == 1):
collisions += 1
occurences.append('northwest: ' + str(i) + ' and ' + str(northwest))
# direction northeast
if (int((north + x) / n) == int(north / n)):
northeast = north + x
if (board[northeast] == 1):
collisions += 1
occurences.append('northeast: ' + str(i) + ' and ' + str(northeast))
# checking below current index
if (i + n * x < max_index):
south = i + n * x
# direction south
if (board[south] == 1):
collisions += 1
occurences.append('south: ' + str(i) + ' and ' + str(south))
# direction southwest
if (int((south - x) / n) == int(south / n)):
southwest = south - x
if (board[southwest] == 1):
collisions += 1
occurences.append('southwest: ' + str(i) + ' and ' + str(southwest))
# direction southeast
if (int((south + x) / n) == int(south / n)) and ((south + x) < max_index):
southeast = south + x
if (board[southeast] == 1):
collisions += 1
occurences.append('southeast: ' + str(i) + ' and ' + str(southeast))
# direction west (for completeness)
if (int((i - x) / n) == int(i / n)) and (i - x >= 0):
west = i - x
if (board[west] == 1):
collisions += 1
occurences.append('west: ' + str(i) + ' and ' + str(west))
# direction east (for completeness)
if (int((i + x) / n) == int(i / n)) and (i + x < max_index):
east = i + x
if (board[east] == 1):
collisions += 1
occurences.append('east: ' + str(i) + ' and ' + str(east))
return [collisions, occurences]
def determine_h_cost(board, n, verbose=False):
''' Function to determine heuristic - total collisions on the board '''
collisions, occurences = find_collisions(board, n)
if verbose:
pprint(occurences)
# return half the collisions, since each colliding position is counted twice from the helper function
return int(collisions / 2)
def find_child(board, n, sideways_move=False):
''' Function to find the successor from all the children by comparing the heuristic values of moving the queens row-wise '''
child = []
current_h_cost = determine_h_cost(board, n)
same_cost_children = []
for row in range(n):
for col in range(n):
# Build a temporary board which changes the position of the queen in the current board
temp_board = []
temp_board.extend(board[:row * n])
new_row = [0] * n
new_row[col] = 1
temp_board.extend(new_row)
temp_board.extend(board[(row + 1) * n:])
temp_h_cost = determine_h_cost(temp_board, n)
if (sideways_move):
# if sideways moves are allowed, and the generated child heuristic cost is less than or equal to the current lowest heuristic cost, save generated child and update current lowest heuristic cost
if (temp_board != board):
if (temp_h_cost < current_h_cost):
child = temp_board.copy()
current_h_cost = temp_h_cost
elif (temp_h_cost == current_h_cost):
same_cost_children.append(temp_board)
x = random.randint(0, len(same_cost_children) - 1)
child = same_cost_children[x]
else:
# if sideways moves are not allowed, and the generated child heuristic cost is less than the current lowest heuristic cost, save generated child and update current lowest heuristic cost
if (temp_board != board) and (temp_h_cost < current_h_cost):
child = temp_board.copy()
current_h_cost = temp_h_cost
return child
def steepest_hill_climbing(board, n, max_iterations=200, verbose=False):
count = 0
''' Steepest Hill climbing without sideways move, returns the current steps and whether the run succeeded or not '''
steps = 0
success = False
current_board = board.copy()
if (verbose):
print_board(current_board, n)
# Until maximum iterations are reached, search for a solution
for i in range(max_iterations):
# Get the least heuristic child from the find child helper function
next_node = find_child(current_board, n).copy()
count += 1#add
if (verbose and len(next_node) != 0):
print_board(next_node, n)
# Update the steps taken for this run
steps += 1
# If we have a child and its heuristic cost is zero, we have a solution
if (len(next_node) != 0) and (determine_h_cost(next_node, n) == 0):
success = True
break
# If we do not get a child, we cannot get a solution
if (len(next_node) == 0):
break
# Make the current child the next node
current_board = next_node.copy()
return steps, success ,count
def steepest_hill_climbing_with_sideways_move(board, n, max_iterations=200, verbose=False):
''' Steepest Hill climbing with sideways move, returns the current steps and whether the run succeeded or not '''
count = 0
steps = 0
success = False
current_board = board.copy()
if (verbose):
print_board(current_board, n)
# Until maximum iterations are reached, search for a solution
for i in range(max_iterations):
# Get the least heuristic child from the find child helper function
next_node = find_child(current_board, n, sideways_move=True).copy()
count += 1#add
if (verbose and len(next_node) != 0):
print_board(next_node, n)
# Update the steps taken for this run
steps += 1
# If we have a child and its heuristic cost is zero, we have a solution
if (len(next_node) != 0) and (determine_h_cost(next_node, n) == 0):
success = True
break
# If we do not get a child, we cannot get a solution
if (len(next_node) == 0):
break
# Make the current child the next node
current_board = next_node.copy()
return steps, success ,count#add
def steepest_hill_climbing_with_random_restart(board, n, max_iterations=200, verbose=False):
''' Steepest Hill climbing with random restart and without sideways move, returns the current steps and whether the run succeeded or not '''
count = 0
steps = 0
success = False
rr = 0
current_board = board.copy()
if (verbose):
print_board(current_board, n)
# Until maximum iterations are reached, search for a solution
for i in range(max_iterations):
# Get the least heuristic child from the find child helper function
next_node = find_child(current_board, n).copy()
count += 1
if (verbose and len(next_node) != 0):
print_board(next_node, n)
# Update the steps taken for this run
steps += 1
# If we do not get a child, restart the search by generating another random board
if (len(next_node) == 0):
next_node = generate_random_board(n)
# Maintain count of restarts made
rr += 1
# If the current node's heuristic cost is zero, we have a solution
if (determine_h_cost(next_node, n) == 0):
success = True
break
# Make the current child the next node
current_board = next_node.copy()
return steps, success, rr ,count
def steepest_hill_climbing_with_random_restart_and_sideways_move(board, n, max_iterations=200, verbose=False):
''' Steepest Hill climbing with random restart and sideways move, returns the current steps and whether the run succeeded or not '''
steps = 0
success = False
rr = 0
current_board = board.copy()
if (verbose):
print_board(current_board, n)
# Until maximum iterations are reached, search for a solution
for i in range(max_iterations):
# Get the least heuristic child from the find child helper function
next_node = find_child(current_board, n, sideways_move=True).copy()
if (verbose and len(next_node) != 0):
print_board(next_node, n)
# Update the steps taken for this run
steps += 1
# If we do not get a child, restart the search by generating another random board
if (len(next_node) == 0):
next_node = generate_random_board(n)
# Maintain count of restarts made
rr += 1
# If the current node's heuristic cost is zero, we have a solution
if (determine_h_cost(next_node, n) == 0):
success = True
break
# Make the current child the next node
current_board = next_node.copy()
return steps, success, rr
iterations = 200
n = input_size_board()
# Script for running functions
start = time.time()
print('爬山法:')
success_rate_steepest_hill_climbing = False
step_count_rate_steepest_hill_climbing_success = 0
step_count_rate_steepest_hill_climbing_failure = 0
sum = 0
for i in range(3):
print('运行 ' + str(i + 1) + ':')
step_count, success, count = steepest_hill_climbing(generate_random_board(n), n, verbose=True)
if (success):
print('成功.')
sum += count
step_count_rate_steepest_hill_climbing_success += step_count
else:
print('失败.')
sum += count
step_count_rate_steepest_hill_climbing_failure += step_count
success_rate_steepest_hill_climbing += success
for i in range(3, iterations):
step_count, success, count = steepest_hill_climbing(generate_random_board(n), n)
sum += count
if (success):
step_count_rate_steepest_hill_climbing_success += step_count
else:
step_count_rate_steepest_hill_climbing_failure += step_count
success_rate_steepest_hill_climbing += success
print('成功率: ' + str(success_rate_steepest_hill_climbing / iterations))
print('失败率: ' + str(1 - (success_rate_steepest_hill_climbing / iterations)))
print('平均成功步数: ' + str(
step_count_rate_steepest_hill_climbing_success / success_rate_steepest_hill_climbing))
print('平均失败步数: ' + str(
step_count_rate_steepest_hill_climbing_failure / (iterations - success_rate_steepest_hill_climbing)))
print('平均结点数:', sum / iterations)
end1 = time.time()
running_time1 = (end1 - start) / iterations
print('爬山法花费时间: %.5f seconds' % running_time1)
print('侧移爬山法:')
sum = 0
success_rate_steepest_hill_climbing_sm = False
step_count_rate_steepest_hill_climbing_success_sm = 0
step_count_rate_steepest_hill_climbing_failure_sm = 0
for i in range(3):
print('运行 ' + str(i + 1) + ':')
step_count, success, count = steepest_hill_climbing_with_sideways_move(generate_random_board(n), n,
verbose=True)
if (success):
print('成功.')
sum += count
step_count_rate_steepest_hill_climbing_success_sm += step_count
else:
print('失败.')
sum += count
step_count_rate_steepest_hill_climbing_failure_sm += step_count
success_rate_steepest_hill_climbing_sm += success
for i in range(3, iterations):
step_count, success, count = steepest_hill_climbing_with_sideways_move(generate_random_board(n), n)
sum += count
if (success):
step_count_rate_steepest_hill_climbing_success_sm += step_count
else:
step_count_rate_steepest_hill_climbing_failure_sm += step_count
success_rate_steepest_hill_climbing_sm += success
print('成功率: ' + str(success_rate_steepest_hill_climbing_sm / iterations))
print('失败率: ' + str(1 - (success_rate_steepest_hill_climbing_sm / iterations)))
print('平均成功步数: ' + str(
step_count_rate_steepest_hill_climbing_success_sm / success_rate_steepest_hill_climbing_sm))
print('平均失败步数: ' + str(
step_count_rate_steepest_hill_climbing_failure_sm / (iterations - success_rate_steepest_hill_climbing_sm)))
print('平均结点数:', sum / iterations)
end2 = time.time()
running_time2 = (end2 - end1) / iterations
print('侧移爬山法花费时间 : %.5f seconds' % running_time2)
print('随机重启爬山法:')
sum = 0
success_rate_steepest_hill_climbing_rr = False
step_count_rate_steepest_hill_climbing_success_rr = 0
step_count_rate_steepest_hill_climbing_failure_rr = 0
random_restarts = 0
for i in range(iterations):
step_count, success, rr, count = steepest_hill_climbing_with_random_restart(generate_random_board(n), n)
random_restarts += rr
if (success):
print('成功.')
sum += count
step_count_rate_steepest_hill_climbing_success_rr += step_count
else:
print('失败.')
sum += count
step_count_rate_steepest_hill_climbing_failure_rr += step_count
success_rate_steepest_hill_climbing_rr += success
print('成功率: ' + str(success_rate_steepest_hill_climbing_rr / iterations))
print('失败率: ' + str(
step_count_rate_steepest_hill_climbing_success_rr / success_rate_steepest_hill_climbing_rr))
print('随机启动次数: ' + str(random_restarts))
print('平均结点数:', sum / iterations)
end3 = time.time()
running_time3 = (end3 - end2) / iterations
print('随机重启爬山法花费时间 : %.5f seconds' % running_time3)
hill_climbing.py:
# _*_ coding:utf-8 _#_
# 开发团队:抛夏
# 开发人员:抛夏
# 开发时间:2022/11/19 21:52
# 文件名称:hill_climbing.py
# 开发工具:PyCharm
# based on code from: https://github.com/aimacode/aima-python
from ast import While
import random
class NQueensProblem:
"""
The problem of placing N queens on an NxN board with none attacking
each other. A state is represented as an N-element array, where
a value of r in the c-th entry means there is a queen at column c,
row r.
This class operates on complete state descriptions where all queens are
on the board in each state (one in each column c). This is in contrast to
the NQueensProblem implementation in aima-python, whose initial state has
no queens on the board, and whose actions method generates all the valid
positions to place a queen in the first free column.
"""
def __init__(self, N=None, state=None):
if N is None:
N = len(state)
if state is None:
state = tuple(0 for _ in range(N))
assert N == len(state)
self.N = N
self.initial = state
def actions(self, state: tuple) -> list:
######################
### Your code here ###
######################
p = list(state)
l = []
m = []
for j in range(len(p)):
for i in range(1, len(p)):
m = p[:]
m[j] = (i + p[j]) % len(p)
l.append(m)
return l
def result(self, state: tuple, action) -> tuple:
"""Return the result of applying `action` to `state`.
Move the queen in the column specified by `action` to the row specified by `action`.
Node.expand calls `result` on each action returned by `actions`.
"""
######################
### Your code here ###
######################
q = tuple(action)
return q
def goal_test(self, state):
"""Check if all columns filled, no conflicts."""
return self.value(state) == 0
def value(self, state):
"""Return 0 minus the number of conflicts in `state`."""
return -self.num_conflicts(state)
def num_conflicts(self, state):
"""Return the number of conflicts in `state`."""
num_conflicts = 0
for (col1, row1) in enumerate(state):
for (col2, row2) in enumerate(state):
if (col1, row1) != (col2, row2):
num_conflicts += self.conflict(row1, col1, row2, col2)
return num_conflicts
def conflict(self, row1, col1, row2, col2):
"""Would putting two queens in (row1, col1) and (row2, col2) conflict?"""
return (row1 == row2 or # same row
col1 == col2 or # same column
row1 - col1 == row2 - col2 or # same \ diagonal
row1 + col1 == row2 + col2) # same / diagonal
def random_state(self):
"""Return a new random n-queens state.
Use this to implement hill_climbing_random_restart.
"""
return tuple(random.choice(range(self.N)) for _ in range(self.N))
class Node:
"""
A node in a search tree. Contains a pointer to the parent (the node
that this is a successor of) and to the actual state for this node.
Delegates problem specific functionality to self.problem.
"""
def __init__(self, problem, state, parent=None, action=None):
"""Create a search tree Node, derived from a parent by an action."""
self.problem = problem
self.state = state
self.parent = parent
self.action = action
self.depth = 0
if parent:
self.depth = parent.depth + 1
def __repr__(self):
return "".format(self.state)
def __lt__(self, node):
return self.state < node.state
def __eq__(self, node):
return self.state == node.state
def value(self):
return self.problem.value(self.state)
def goal_test(self):
return self.problem.goal_test(self.state)
def expand(self):
"""List the nodes reachable from this node."""
state = self.state
problem = self.problem
return [
Node(
state=problem.result(state, action),
problem=problem,
parent=self,
action=action,
)
for action in problem.actions(state)
]
def best_of(self, nodes):
"""Return the best Node from a list of Nodes, based on problem.value.
Sorting the nodes is not the best for runtime or search performance,
but it ensures that the result is deterministic for the purpose of
this assignment.
"""
return max(
sorted(nodes),
key=lambda node: node.value(),
)
def hill_climbing(problem):
"""
[Figure 4.2] in the textbook.
From the initial node, keep choosing the neighbor with highest value,
stopping when no neighbor is better.
"""
current = Node(problem=problem, state=problem.initial)
while True:
if current.goal_test():
break
neighbours = current.expand()
if not neighbours:
break
neighbour = current.best_of(neighbours)
if neighbour.value() <= current.value():
break
current = neighbour
return current.state
def hill_climbing_instrumented(problem):
"""
Find the same solution as `hill_climbing`, and return a dictionary
recording the number of nodes expanded, and whether the problem was
solved.
"""
######################
### Your code here ###
######################
expand = 0
bool1 = False
current = Node(problem=problem, state=problem.initial)
while True:
if current.goal_test():
bool1 = True
break
neighbours = current.expand()
expand = expand + 1
if not neighbours:
break
neighbour = current.best_of(neighbours)
if neighbour.value() <= current.value():
break
current = neighbour
return {
"expanded": expand,
"solved": bool1,
"best_state": current.state,
}
def hill_climbing_sideways(problem, max_sideways_moves):
"""
When the search would terminate because the best neighbour doesn't
have a higher value than the current state, continue the search if
the the best neighbour's value is equal to that of the current state.
But don't do this more than `max_sideways_moves` times. Watch out for
off by one errors, and don't forget to return early if the search finds
a goal state.
"""
######################
### Your code here ###
######################
current = Node(problem=problem, state=problem.initial)
expand = 0
move = 0
bool1 = False
while True:
if current.goal_test():
bool1 = True
break
neighbours = current.expand()
expand = expand + 1
if not neighbours:
break
neighbour = current.best_of(neighbours)
if neighbour.value() <= current.value():
a = list(current.state)
'''q = random.randint(0,len(current.state)-1)
p = random.randint(0,len(current.state)-1)
while(p==q):
p = random.randint(0,len(current.state)-1)'''
t = 0
t = a[0]
a[0] = a[1]
a[1] = t
if move >= max_sideways_moves:
break
move = move + 1
current.state = tuple(a)
if neighbour.value() >= current.value():
current = neighbour
return {
"expanded": expand,
"solved": bool1,
"best_state": current.state,
"sideways_moves": move,
}
def hill_climbing_random_restart(problem, max_restarts):
"""
When the search would terminate because the best neighbour doesn't
have a higher value than the current state, generate a new state to
continue the search from (using problem.random_state).
But don't do this more than `max_restarts` times. Watch out for
off by one errors, and don't forget to return early if the search finds
a goal state.
To get consistent results each time, call random.seed(YOUR_FAVOURITE_SEED)
before calling this function.
"""
######################
### Your code here ###
######################
current = Node(problem=problem, state=problem.initial)
expand = 0
bool1 = False
restart = 0
x = len(current.state)
while True:
if current.goal_test():
bool1 = True
break
neighbours = current.expand()
expand = expand + 1
if not neighbours:
break
neighbour = current.best_of(neighbours)
if neighbour.value() <= current.value():
a = tuple(random.choice(range(x)) for _ in range(x))
if (restart >= max_restarts):
break
current.state = a
restart = restart + 1
else:
current = neighbour
return {
"expanded": expand,
"solved": bool1,
"best_state": current.state,
"restarts": restart,
}
test.py(作业要求,自己用可以不要这个,可以参考里面的运行函数):
# _*_ coding:utf-8 _#_
# 开发团队:抛夏
# 开发人员:抛夏
# 开发时间:2022/11/19 21:49
# 文件名称:test.py
# 开发工具:PyCharm
"""
Run test_all() to test NQueensProblem, hill_climbing_instrumented, hill_climbing_sideways and hill_climbing_random_restart.
Or run their individual tests. Methods to be tested are imported from hill_climbing.py in the same directory as this file.
"""
import random
from functools import wraps
from hill_climbing import (
NQueensProblem,
hill_climbing_instrumented,
hill_climbing_sideways,
hill_climbing_random_restart,
)
SEED = 1
VERBOSE = True
# {state: problem.result(state, problem.actions(state))}
action_and_result_examples = {
(0, 0): [(1, 0), (0, 1)],
(0, 1): [(1, 1), (0, 0)],
(0, 0, 0, 0): [ # 4 queens, all in row 0
(1, 0, 0, 0),
(2, 0, 0, 0),
(3, 0, 0, 0),
(0, 1, 0, 0),
(0, 2, 0, 0),
(0, 3, 0, 0),
(0, 0, 1, 0),
(0, 0, 2, 0),
(0, 0, 3, 0),
(0, 0, 0, 1),
(0, 0, 0, 2),
(0, 0, 0, 3),
],
(0, 1, 2, 3): [ # 4 queens, arranged diagonally
(1, 1, 2, 3),
(2, 1, 2, 3),
(3, 1, 2, 3),
(0, 0, 2, 3),
(0, 2, 2, 3),
(0, 3, 2, 3),
(0, 1, 0, 3),
(0, 1, 1, 3),
(0, 1, 3, 3),
(0, 1, 2, 0),
(0, 1, 2, 1),
(0, 1, 2, 2),
],
}
# {args: f(*args)}
# {(state,): hill_climbing_instrumented(state)}
hill_climbing_instrumented_examples = {
((0, 0, 0, 0),): {
"expanded": 3,
"solved": True,
"best_state": (2, 0, 3, 1),
},
((0, 1, 2, 3),): {
"expanded": 3,
"solved": False,
"best_state": (1, 0, 2, 3),
},
}
# {args: f(*args)}
# {(state, max_sideways_moves): hill_climbing_sideways(state, max_sideways_moves)}
hill_climbing_sideways_examples = {
((0, 0, 0, 0), 1): {
"expanded": 3,
"solved": True,
"best_state": (2, 0, 3, 1),
"sideways_moves": 0,
},
((0, 1, 2, 3), 1): {
"expanded": 5,
"solved": False,
"best_state": (1, 2, 0, 3),
"sideways_moves": 1,
},
((0, 0, 0, 0), 10): {
"expanded": 3,
"solved": True,
"best_state": (2, 0, 3, 1),
"sideways_moves": 0,
},
((0, 1, 2, 3), 10): {
"expanded": 6,
"solved": True,
"best_state": (1, 3, 0, 2),
"sideways_moves": 2,
},
((0, 0, 0, 0, 0, 0, 0, 0), 10): {
"expanded": 17,
"solved": False,
"best_state": (4, 0, 0, 3, 6, 2, 7, 1),
"sideways_moves": 10,
},
((0, 1, 2, 3, 4, 5, 6, 7), 10): {
"expanded": 18,
"solved": False,
"best_state": (3, 0, 7, 4, 1, 5, 2, 6),
"sideways_moves": 10,
},
((0, 0, 0, 0, 0, 0, 0, 0), 100): {
"expanded": 107,
"solved": False,
"best_state": (4, 0, 0, 3, 6, 2, 7, 1),
"sideways_moves": 100,
},
((0, 1, 2, 3, 4, 5, 6, 7), 100): {
"expanded": 108,
"solved": False,
"best_state": (3, 0, 7, 4, 1, 5, 2, 6),
"sideways_moves": 100,
},
}
# {args: f(*args)}
# {(state, max_restarts): hill_climbing_random_restart(state, max_restarts)}
hill_climbing_random_restart_examples = {
((0, 0, 0, 0), 1): {
"expanded": 3,
"solved": True,
"best_state": (2, 0, 3, 1),
"restarts": 0,
},
((0, 1, 2, 3), 1): {
"expanded": 5,
"solved": False,
"best_state": (1, 3, 2, 0),
"restarts": 1,
},
((0, 0, 0, 0), 10): {
"expanded": 3,
"solved": True,
"best_state": (2, 0, 3, 1),
"restarts": 0,
},
((0, 1, 2, 3), 10): {
"expanded": 8,
"solved": True,
"best_state": (2, 0, 3, 1),
"restarts": 2,
},
((0, 0, 0, 0, 0, 0, 0, 0), 10): {
"expanded": 24,
"solved": True,
"best_state": (5, 1, 6, 0, 2, 4, 7, 3),
"restarts": 4,
},
((0, 1, 2, 3, 4, 5, 6, 7), 10): {
"expanded": 24,
"solved": True,
"best_state": (5, 1, 6, 0, 2, 4, 7, 3),
"restarts": 4,
},
}
def verbose_test(test):
@wraps(test)
def wrapper(*args, **kwargs):
errors = test(*args, **kwargs)
if not VERBOSE:
return errors
if not errors:
print("PASSED:", test.__name__)
return errors
print()
print("FAILED:", test.__name__)
for problem, error in errors.items():
print("\t", problem, sep="")
print("\tyour result:", error["result"])
print("\ttrue result:", error["example_result"])
if "keys" in error:
print("\tthese keys were in error:", error["keys"])
print()
return errors
return wrapper
def prefix_errors(test):
@wraps(test)
def wrapper(*args, **kwargs):
errors = test(*args, **kwargs)
return {
(test.__name__, problem): error
for problem, error in errors.items()
}
return wrapper
def test_all():
"""Run all tests.
Call get_all_prefixed_errors to get all errors as a dict.
"""
get_all_prefixed_errors()
def get_all_prefixed_errors():
return {
**prefix_errors(test_action_and_result)(),
**prefix_errors(test_hill_climbing_instrumented)(),
**prefix_errors(test_hill_climbing_sideways)(),
**prefix_errors(test_hill_climbing_random_restart)(),
}
@verbose_test
def test_action_and_result():
errors = {}
for state, example_result in action_and_result_examples.items():
problem = NQueensProblem(state=state)
result = [
problem.result(problem.initial, action)
for action in problem.actions(problem.initial)
]
if set(result) != set(example_result):
errors[state] = {
"example_result": example_result,
"result": result,
}
return errors
@verbose_test
def test_hill_climbing_instrumented():
return hill_climbing_test(hill_climbing_instrumented)
@verbose_test
def test_hill_climbing_sideways():
return {
**vanilla_check(hill_climbing_sideways),
**hill_climbing_test(hill_climbing_sideways),
}
@verbose_test
def test_hill_climbing_random_restart():
return {
**vanilla_check(hill_climbing_random_restart),
**hill_climbing_test(hill_climbing_random_restart),
}
@prefix_errors
def vanilla_check(hill_climbing_method, examples=hill_climbing_instrumented_examples):
"""Check if hill_climbing_method with a restart / sideways move limit of 0 returns results identical to hill_climbing_instrumented."""
def hill_climbing_proxy(problem):
return hill_climbing_method(problem, 0)
return hill_climbing_test(hill_climbing_proxy, examples=examples)
@prefix_errors
def hill_climbing_test(hill_climbing_method, examples=None):
"""Check if provided hill_climbing_method has the correct output."""
if examples is None:
examples = globals()[hill_climbing_method.__name__ + "_examples"]
answers = generate_answers(hill_climbing_method, problems=examples)
errors = {}
for problem, example_result in examples.items():
result = answers[problem]
keys = []
for key, value in example_result.items():
if result[key] != value:
keys.append(key)
if keys:
errors[problem] = {
"example_result": example_result,
"result": result,
"keys": keys,
}
return errors
def generate_answers(hill_climbing_method, problems=None):
"""Return dictionary of results of running hill_climbing_method on problems."""
if problems is None:
examples = globals()[hill_climbing_method.__name__ + "_examples"]
answers = {}
for key in problems:
state, *args = key
problem = NQueensProblem(state=state)
random.seed(SEED)
result = hill_climbing_method(problem, *args)
answers[key] = result
return answers
test_action_and_result()
test_hill_climbing_instrumented()
test_hill_climbing_sideways()
test_hill_climbing_random_restart()
简单记一下自己对python看法的改变..以前一直觉得这种能直接使用的库和函数太多的语言(区别于c和c++),不能完全理解原理就应用,很违背自己一贯的思维方式也很难受,但是现在觉得这恰好能更方便处理很多更高级的问题,因为人的精力是有限的不能一直只关注底层的逻辑,更流畅高效地应用各种库也是一种能力..尤其是在学过opencv之后,这种要解决的问题更多的是数学方面的,那简便的函数工具就是非常必要的了。但是作为初学者,还是不能降低对自己的要求 要尽量多花时间弄懂每一个的原理~