import numpy as np
import copy
import random
import math
target = [[1, 2, 3], [8, 0, 4], [7, 6, 5]]
state = [[1, 3, 0], [8, 2, 4], [7, 6, 5]]
state_queen = [random.randint(0, 7) for i in range(8)]
state_queen = np.eye(8)[state_queen].T
def loss(state, target=None, s=1):
#八数码
state = np.array(state)
if s==1:
target = np.array(target)
loss_sum = 0
for i in range(9):
loss_sum += sum(sum(abs(np.argwhere(state == i) - np.argwhere(target == i))))
#八皇后
if s==0:
attack_pair = 0
for i in range(8):
for j in range(8):
if state[j][i] == 1:
attack_pair += sum(state[j])-1 + sum(state.T[i])-1
k = i-1
l = j-1
while k >= 0 and l >= 0:
attack_pair += state[l][k]
k = k-1
l = l-1
k = i + 1
l = j + 1
while k <= 7 and l <= 7:
attack_pair += state[l][k]
k = k + 1
l = l + 1
k = i - 1
l = j + 1
while k >= 0 and l <= 7:
attack_pair += state[l][k]
k = k - 1
l = l + 1
k = i + 1
l = j - 1
while k <= 7 and l >= 0:
attack_pair += state[l][k]
k = k + 1
l = l - 1
loss_sum = attack_pair/2
return loss_sum
def generating_sons(state, s=1):
state = np.array(state)
sons = []
if s == 1:
hole_loc = np.squeeze(np.argwhere(state == 0))
if hole_loc[0]-1 >= 0:
new_son = copy.deepcopy(state)
new_son[hole_loc[0]][hole_loc[1]] = new_son[hole_loc[0]-1][hole_loc[1]]
new_son[hole_loc[0]-1][hole_loc[1]] = 0
sons.append(copy.deepcopy(new_son))
if hole_loc[1]-1 >= 0:
new_son = copy.deepcopy(state)
new_son[hole_loc[0]][hole_loc[1]] = new_son[hole_loc[0]][hole_loc[1]-1]
new_son[hole_loc[0]][hole_loc[1] - 1] = 0
sons.append(copy.deepcopy(new_son))
if hole_loc[0]+1 <= 2:
new_son = copy.deepcopy(state)
new_son[hole_loc[0]][hole_loc[1]] = new_son[hole_loc[0]+1][hole_loc[1]]
new_son[hole_loc[0]+1][hole_loc[1]] = 0
sons.append(copy.deepcopy(new_son))
if hole_loc[1]+1 <= 2:
new_son = copy.deepcopy(state)
new_son[hole_loc[0]][hole_loc[1]] = new_son[hole_loc[0]][hole_loc[1]+1]
new_son[hole_loc[0]][hole_loc[1] + 1] = 0
sons.append(copy.deepcopy(new_son))
if s == 0:
for i in range(8):
for j in range(8):
if state[j][i] == 1:
new_son = copy.deepcopy(state)
new_son[j][i] = 0
for k in range(1, 8):
new_son[(j+k) % 8][i] = 1
sons.append(copy.deepcopy(new_son))
new_son[(j+k) % 8][i] = 0
return sons
def randomly_generate_one_state(state=None):
if state is None:
state_queen = [random.randint(0, 7) for i in range(8)]
state_queen = np.eye(8)[state_queen].T
return state_queen
for i in range(random.randint(0, 100)):
sons = generating_sons(state)
son = randomly_choose_one_son(sons)
state = son
return state
def randomly_choose_one_son(sons):
return sons[random.randint(0, len(sons)-1)]
def climbing_mountain_steepest(state, target=None, s=1):
state = copy.deepcopy(state)
target = copy.deepcopy(target)
count = 0
while loss(state, target, s) != 0:
sons = generating_sons(state, s)
loss_sons = []
for son in sons:
loss_sons.append(loss(son, target, s))
state = sons[np.argmin(np.array(loss_sons))]
count += 1
if count > 1000:
return False
return state, count
def climbing_mountain_random_better(state, target=None, s=1):
state = copy.deepcopy(state)
target = copy.deepcopy(target)
count = 0
while loss(state, target, s) != 0:
inner_count = 0
if count > 1000:
return False
sons = generating_sons(state, s)
son = randomly_choose_one_son(sons)
while loss(son, target, s) > loss(state, target, s):
inner_count += 1
son = randomly_choose_one_son(sons)
if inner_count > 300:
return False
state = son
count += 1
return state, count
def climbing_mountain_random_restart():
state = randomly_generate_one_state()
out = climbing_mountain_steepest(state, s=0)
if out is not False:
step = out[1]
else:
step = 0
while out is False:
step += 1000
state = randomly_generate_one_state()
out = climbing_mountain_steepest(state, s=0)
step += out[1]
return out, step
def sim_annealing(state, target=None, s=1, init_temp=1000, temp_iter_num=1, cooling_factor=0.95):
state = copy.deepcopy(state)
target = copy.deepcopy(target)
T = init_temp
count = 0
step = 0
while loss(state, target, s) != 0:
sons = generating_sons(state, s)
son = randomly_choose_one_son(sons)
delta_loss = loss(state, target, s) - loss(son, target, s)
count += 1
if count > 4000:
return False
if delta_loss > 0:
state = son
T = T*cooling_factor
step += 1
else:
prob = math.exp(delta_loss/T)
T = T * cooling_factor
if prob > random.random():
state = son
step += 1
else:
continue
return state, step
def main():
num_rb_counter = [0, 0]
num_sa_counter = [0, 0]
num_sp_conter = [0, 0]
queen_rb_counter = [0, 0]
queen_sa_counter = [0, 0]
queen_sp_conter = [0, 0]
queen_rr_counter = [0, 0]
for i in range(1000):
state = randomly_generate_one_state(target)
rb = climbing_mountain_random_better(state, target)
sp = climbing_mountain_steepest(state, target)
sa = sim_annealing(state, target)
if rb is not False:
num_rb_counter[0] += 1
num_rb_counter[1] += rb[1]
if sp is not False:
num_sp_conter[0] += 1
num_sp_conter[1] += sp[1]
if sa is not False:
num_sa_counter[0] += 1
num_sa_counter[1] += sa[1]
state = randomly_generate_one_state()
rb_q = climbing_mountain_random_better(state, s=0)
sp_q = climbing_mountain_steepest(state, s=0)
sa_q = sim_annealing(state, s=0)
rr_q = climbing_mountain_random_restart()
if rb_q is not False:
queen_rb_counter[0] += 1
queen_rb_counter[1] += rb_q[1]
if sp_q is not False:
queen_sp_conter[0] += 1
queen_sp_conter[1] += sp_q[1]
if sa_q is not False:
queen_sa_counter[0] += 1
queen_sa_counter[1] += sa_q[1]
if rr_q is not False:
queen_rr_counter[0] += 1
queen_rr_counter[1] += rr_q[1]
print(i, [num_sp_conter, num_rb_counter, num_sa_counter],
[queen_sp_conter, queen_rb_counter, queen_sa_counter, queen_rr_counter])
main()