f = {
0: {
'0': 2,
'1': 1
},
1: {
'00': 2,
'01': 3,
'10': 2,
'11': 0
},
2: {
'000': 0,
'001': 1,
'010': 1,
'011': 0,
'100': 2,
'101': 0,
'110': 0,
'111': 0
}
}
import random
def generate_sequence(N):
# TODO
'''
generates an N random bits (0, 1) sequence
Parameters:
-----------
N : number of bits in the sequence
Returns:
--------
sequence: sequence of N bits
'''
sequence=[]
for i in range(N) :
sequence.append(random.choice(['0', '1'])) # generate a random sequence of N bits (0, 1)
return sequence
def compute_fitness(sequence, K):
# TODO
'''
computes the fitness of sequence, with respect to K, according to table f
Parameters:
-----------
sequence : N-bits sequence
K : parameter K (0, 1, or 2)
Returns:
--------
fitness: fitness value of sequence
'''
seq = str(sequence)
N = len(seq)
fitness = 0
if K == 0:
# f0: 0->2, 1->1
for bit in seq:
fitness += 2 if bit == '0' else 1
elif K == 1:
# f1: 00->2, 01->3, 10->2, 11->0
for i in range(N):
pair = seq[i] + seq[(i+1) % N]
if pair == '00': fitness += 2
elif pair == '01': fitness += 3
elif pair == '10': fitness += 2
elif K == 2:
# f2: 000->0 001->1 010->1 011->0 100->2 101->0 110->0 111->0
for i in range(N):
triple = seq[i] + seq[(i+1) % N] + seq[(i+2) % N]
if triple == '001' or triple == '010': fitness += 1
elif triple == '100': fitness += 2
return fitness
def neighbors(sequence):
'''
returns all neighbors of sequence ()
Parameters:
-----------
sequence : N-bits sequence
Returns:
--------
generator of neighbors of sequence
'''
for i in range(len(sequence)):
if sequence[i] == '0':
new = '1'
else: new = '0'
yield (sequence[:i] + new + sequence[i + 1:])
# generate all neighbors that differ in 1 bit
def mean_steps(samples):
'''
returns mean of steps taken to find solution (for deterministic)
Parameters:
-----------
samples : samples of deterministic_hillclimb runs
Returns:
--------
mean steps
'''
# get mean of steps needed to find solution (sum of samples' steps/number of samples)
return sum(x[2] for x in samples)/len(samples)
def generate_samples(hillclimb_method, K):
'''
generates 50 samples (solutions) for the hillclimb method (deterministic/probabilistic)
Parameters:
-----------
hillclimb_method : deterministic_hillclimb/probabilistic_hillclimb
K : parameter K (0, 1, or 2)
Returns:
--------
generator of samples/solutions (sequence, fitness, number of steps)
'''
if K not in [0, 1, 2]:
raise Exception("Invalid K")
# run for 50 times to get 50 samples/solutions
for i in range(50):
# generate initial sequence
initial_sequence = generate_sequence(N=21)
# get solution, its fitness, number of steps taken to find solution
x, f_x, s = hillclimb_method(initial_sequence, K)
yield (x, f_x, s)
def deterministic_hillclimb(sequence, K):
# TODO
'''
performs deterministic_hillclimb
Parameters:
-----------
sequence : N-bits sequence
K : parameter K (0, 1, or 2)
Returns:
--------
sequence : optimal/fittest sequence found
max_fitness : fitness value of sequence
steps: steps it took to reach optimum
'''
current_solution = sequence
current_value = compute_fitness(current_solution, K)
steps = 0
# 记录每次迭代的最佳值
best_values = [current_value]
# 迭代寻找更好的解
for i in range(50): # 最多迭代50次
# 生成邻近解
neighbor = neighbors(current_solution,K)
neighbor_value = compute_fitness(neighbor, K)
# 如果邻近解更优,则更新当前解
if neighbor_value < current_value:
current_solution = neighbor
current_value = neighbor_value
else:
pass # 没有改进,保持当前解不变
best_values.append(current_value) # 记录当前最佳值
return current_solution, current_value, best_values
# dictionary to save deterministic_hillclimb samples (sequence, max_fitness, steps)
deterministic_samples = {}
# dictionary to save number of steps to perform probabilistic hillclimb
probabilistic_steps = {}
# run deterministic_hillclimb, get mean steps
for K in [0, 1, 2]:
# for each K, generate 50 deterministic_hillclimb solutions, and save them
deterministic_samples[K] = list(generate_samples(deterministic_hillclimb, K))
# for each K, save the number of steps to take (10*mean steps taken for deterministic_hillclimb)
probabilistic_steps[K] = 10*round(mean_steps(deterministic_samples[K]))
def probabilistic_hillclimb(sequence, K):
# TODO
'''
performs probabilistic_hillclimb
Parameters:
-----------
sequence : N-bits sequence
K : parameter K (0, 1, or 2)
Returns:
--------
sequence : optimal/fittest sequence found
max_fitness : fitness value of sequence
steps: steps corresponding to parameter K
'''
current_solution = sequence
current_value = compute_fitness(current_solution, K)
steps = 0
max_iterations = probabilistic_steps[K]
import numpy as np
for _ in range(max_iterations):
# Generate all neighbors
neighbor_list = []
for i in range(len(current_solution)):
neighbor = list(current_solution)
neighbor[i] = '1' if neighbor[i] == '0' else '0'
neighbor_list.append(''.join(neighbor))
neighbor_values = [compute_fitness(neighbor, K) for neighbor in neighbor_list]
# Calculate selection probabilities (higher fitness gets higher probability)
total = sum(neighbor_values)
if total == 0:
probabilities = [1/len(neighbor_values)] * len(neighbor_values)
else:
probabilities = [v/total for v in neighbor_values]
# Randomly select a neighbor based on probabilities
selected_index = np.random.choice(len(neighbor_list), p=probabilities)
selected_neighbor = neighbor_list[selected_index]
selected_value = neighbor_values[selected_index]
# Update current solution if better
if selected_value > current_value:
current_solution = selected_neighbor
current_value = selected_value
steps += 1
return current_solution, current_value, steps
# dictionary to save probabilistic_hillclimb samples (sequence, max_fitness, steps)
probabilistic_samples = {}
# run probabilistic_hillclimb
for K in [0, 1, 2]:
# for each K, generate 50 probabilistic_hillclimb solutions, and save them
probabilistic_samples[K] = list(generate_samples(probabilistic_hillclimb, K))
def hamming_distance(sequence1, sequence2):
# TODO
'''
returns hamming distance between sequence1 and sequence2
Parameters:
-----------
sequence1 : N-bits sequence
sequence2 : N-bits sequence
Returns:
--------
distance : hamming distance between sequence1 and sequence2
'''
xor_result = sequence1 ^ sequence2
return bin(xor_result).count('1')
import matplotlib.pyplot as plt
# 分析并绘制汉明距离
def analyze_and_plot_hamming(N=21, num_runs=50):
# 存储结果
hamming_results = {}
for K in [0, 1, 2]:
print(f"处理 K={K}")
hamming_results[K] = {'deterministic': [], 'probabilistic': []}
# 存储解
det_solutions = []
prob_solutions = []
# 运行实验
for run in range(num_runs):
seq = generate_sequence(N)
# 确定性爬山
det_sol, _, _ = deterministic_hillclimb(seq, K)
det_solutions.append(det_sol)
# 概率性爬山
prob_sol, _, _ = probabilistic_hillclimb(seq, K)
prob_solutions.append(prob_sol)
# 计算汉明距离
hamming_results[K]['deterministic'] = get_all_hamming_distances(det_solutions)
hamming_results[K]['probabilistic'] = get_all_hamming_distances(prob_solutions)
# 绘制结果
plot_hamming_results(hamming_results)
return hamming_results
# 计算所有解对之间的汉明距离
def get_all_hamming_distances(solutions):
distances = []
n = len(solutions)
for i in range(n):
for j in range(i+1, n):
dist = hamming_distance(solutions[i], solutions[j])
distances.append(dist)
return distances
这是我的全部的代码,请编写 Plot and analyze pairwise hamming distances for all methods and K values的答案代码
最新发布