启发式搜索算法

模拟退火:
  算法步骤:给出初始温度,初始解,退火系数等参数。(1)在温度没有达到降到最终设定的温度时,进行退火过程即进行循环迭代。(2)在该温度下,产生新解,并计算目标函数值。如果目标函数值更优,接受新解。否则,会以一定的概率接受错误解。该过程完成,即完成一次退火。算法的核心,在与接受概率的设定。
反应在代码上:外循环控制执行次数(进行退火)。(2)内循环搜索最优解。

遗传算法:遗传算法本质上,是一种高效的启发式搜索算法。
  算法步骤:(1)产生种群,在此,相当于产生染色体,本质上是对问题的解进行编码。常见的编码方案有:二进制编码,浮点编码等。
(2)计算适应度:适应度的评价由适应度函数(一般和目标函数有关),计算适应度的过程需要解码。
(3)选择:常用方法有:轮盘赌选择,最佳保留选择等。选择的目的,淘汰适应度低的个体,换句话说将劣解舍弃。
(4)交叉:交叉的目的是产生,新的解。这也体现了搜索算法的特点。交叉操作有:单点交叉,两点交叉等。
(5)变异:变异也能够产生新的解,加入变异操作,可以增大解空间,扩大搜索解的范围。变异方法有:均匀变异,非均匀变异等。
经过上述一轮操作后,就产生了一组解。若未达到最大迭代次数,则重复迭代。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D

DNA_SIZE = 24
POP_SIZE = 200
CROSSOVER_RATE = 0.8
MUTATION_RATE = 0.005
N_GENERATIONS = 50
X_BOUND = [-3, 3]
Y_BOUND = [-3, 3]

def F(x, y):
    return 3*(1-x)**2*np.exp(-(x**2)-(y+1)**2)- 10*(x/5 - x**3 - y**5)*np.exp(-x**2-y**2)- 1/3**np.exp(-(x+1)**2 - y**2)

def plot_3d(ax):
    X = np.linspace(*X_BOUND, 100)
    Y = np.linspace(*Y_BOUND, 100)
    X,Y = np.meshgrid(X, Y)
    Z = F(X, Y)
    ax.plot_surface(X,Y,Z,rstride=1,cstride=1,cmap=cm.coolwarm)
    ax.set_zlim(-10,10)
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    plt.pause(3)
    plt.show()
    
def get_fitness(pop):
    x,y = translateDNA(pop)
    pred = F(x, y)
    return (pred - np.min(pred)) #减去最小的适应度是为了防止适应度出现负数,通过这一步fitness的范围为[0, np.max(pred)-np.min(pred)]

def translateDNA(pop): #pop表示种群矩阵,一行表示一个二进制编码表示的DNA,矩阵的行数为种群数目
    x_pop = pop[:,1::2]#奇数列表示X,从索引列1开始,加入了步长2
    y_pop = pop[:,::2] #偶数列表示y,从索引列1开始,加入了步长2

    #pop:(POP_SIZE,DNA_SIZE)*(DNA_SIZE,1) --> (POP_SIZE,1)
    x = x_pop.dot(2**np.arange(DNA_SIZE)[::-1])/float(2**DNA_SIZE-1)*(X_BOUND[1]-X_BOUND[0])+X_BOUND[0]
    y = y_pop.dot(2**np.arange(DNA_SIZE)[::-1])/float(2**DNA_SIZE-1)*(Y_BOUND[1]-Y_BOUND[0])+Y_BOUND[0]
    return x,y

def crossover_and_mutation(pop, CROSSOVER_RATE = 0.8):
    new_pop = []
    for father in pop:		#遍历种群中的每一个个体,将该个体作为父亲
        child = father		#孩子先得到父亲的全部基因(这里我把一串二进制串的那些0,1称为基因)
        if np.random.rand() < CROSSOVER_RATE:			#产生子代时不是必然发生交叉,而是以一定的概率发生交叉
            mother = pop[np.random.randint(POP_SIZE)]	#再种群中选择另一个个体,并将该个体作为母亲
            cross_points = np.random.randint(low=0, high=DNA_SIZE*2)	#随机产生交叉的点
            child[cross_points:] = mother[cross_points:]		#孩子得到位于交叉点后的母亲的基因
        mutation(child)	#每个后代有一定的机率发生变异
        new_pop.append(child)

    return new_pop

def mutation(child, MUTATION_RATE=0.003):
    if np.random.rand() < MUTATION_RATE: 				#以MUTATION_RATE的概率进行变异
        mutate_point = np.random.randint(0, DNA_SIZE*2)	#随机产生一个实数,代表要变异基因的位置
        child[mutate_point] = child[mutate_point]^1 	#将变异点的二进制为反转

def select(pop, fitness):    # nature selection wrt pop's fitness
    idx = np.random.choice(np.arange(POP_SIZE), size=POP_SIZE, replace=True,
                           p=(fitness)/(fitness.sum()) )
    return pop[idx]

def print_info(pop):
    fitness = get_fitness(pop)
    max_fitness_index = np.argmax(fitness)
    print("max_fitness:", fitness[max_fitness_index])
    x,y = translateDNA(pop)
    print("最优的基因型:", pop[max_fitness_index])
    print("(x, y):", (x[max_fitness_index], y[max_fitness_index]))

if __name__ == "__main__":
    fig = plt.figure()
    ax = Axes3D(fig)
    plt.ion()#将画图模式改为交互模式,程序遇到plt.show不会暂停,而是继续执行
    plot_3d(ax)

    pop = np.random.randint(2, size=(POP_SIZE, DNA_SIZE*2)) #matrix (POP_SIZE, DNA_SIZE)
    for _ in range(N_GENERATIONS):#迭代N代
        x,y = translateDNA(pop)
        if 'sca' in locals():
            sca.remove()
        sca = ax.scatter(x, y, F(x,y), c='black', marker='o')
        plt.show()
        plt.pause(0.1)
        pop = np.array(crossover_and_mutation(pop, CROSSOVER_RATE))
        #F_values = F(translateDNA(pop)[0], translateDNA(pop)[1])#x, y --> Z matrix
        fitness = get_fitness(pop)
        pop = select(pop, fitness) #选择生成新的种群
    print_info(pop)
    plt.ioff()
    plot_3d(ax)

  粒子群算法:作为启发式搜索算法,和遗传算法在一定程度上,具有相似性,只不过产生新解的方式不同。
算法流程:(1)产生群体的位置和速度。位置:即当前解。速度:更新解的方式。
(2)计算适应度函数,评估解的质量。这点和遗传算法是类似的。
(3)对于每一个粒子,更新它的全局最优位置。当前解更优,用当前解更新该例子的全局最优解。
(4)更新全体最优解,用所有粒子中最优的解来更新全局最优解。
(5)更新粒子的位置和速度,即产生新解,以及下次的更新方式。
(6)算法迭代。

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
启发式搜索算法是一种通过探索问题空间中的有希望的区域来寻找解决方案的算法。它通常用于解决那些传统的搜索算法难以解决的问题,例如NP难问题。常见的启发式搜索算法包括遗传算法、蚁群算法、爬山算法和禁忌搜索算法等。 以下是两种启发式搜索算法的Python实现: 1.遗传算法 ```python import random # 适应度函数 def fitness(individual): return sum(individual) # 个体类 class Individual: def __init__(self, chromosome): self.chromosome = chromosome self.fitness = fitness(chromosome) # 交叉操作 def crossover(self, other): pivot = random.randint(0, len(self.chromosome) - 1) child1 = self.chromosome[:pivot] + other.chromosome[pivot:] child2 = other.chromosome[:pivot] + self.chromosome[pivot:] return Individual(child1), Individual(child2) # 变异操作 def mutate(self): index = random.randint(0, len(self.chromosome) - 1) self.chromosome[index] = 1 - self.chromosome[index] self.fitness = fitness(self.chromosome) # 种群类 class Population: def __init__(self, size, chromosome_length): self.size = size self.individuals = [] for i in range(size): chromosome = [random.randint(0, 1) for j in range(chromosome_length)] self.individuals.append(Individual(chromosome)) # 选择操作 def selection(self): return random.choices(self.individuals, weights=[i.fitness for i in self.individuals], k=2) # 进化操作 def evolve(self): new_population = [] for i in range(self.size): parent1, parent2 = self.selection() child1, child2 = parent1.crossover(parent2) child1.mutate() child2.mutate() new_population.extend([child1, child2]) self.individuals = new_population # 测试 population = Population(10, 5) for i in range(10): print(f"Generation {i}: {[j.chromosome for j in population.individuals]}") population.evolve() print(f"Generation {i+1}: {[j.chromosome for j in population.individuals]}") ``` 2.爬山算法 ```python import random # 目标函数 def objective_function(x): return x ** 2 # 爬山算法 def hill_climbing(start, objective_function, step_size=0.01, max_iter=1000): current = start for i in range(max_iter): left = objective_function(current - step_size) right = objective_function(current + step_size) if left > objective_function(current) and left > right: current -= step_size elif right > objective_function(current) and right > left: current += step_size else: break return current # 测试 start = random.uniform(-10, 10) result = hill_climbing(start, objective_function) print(f"Start: {start}, Result: {result}") ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值