人工智能头歌--群智能算法(仅代码)

如果结果并非如你所愿,那就在尘埃落定前奋力一搏。

                                                                                   ——《夏目友人帐》


目录

# 第1关:模拟退火算法

# 第2关:遗传算法

# 第3关:蚁群算法

# 第4关:粒子群算法


# 第1关:模拟退火算法

import math
import time
import random

# 初始温度
T = 50000
# 最低温度
T_end = 1e-8
# 在每个温度下的迭代次数
L = 100
# 退火系数
delta = 0.98

# 31个城市的坐标
citys = [[1304, 2312], [3639, 1315], [4177, 2244], [3712, 1399], [3488, 1535], [3326, 1556], [3238, 1229], [4196, 1004],
         [4312, 790], [4386, 570], [3007, 1970], [2562, 1756], [2788, 1491], [2381, 1676], [1332, 695], [3715, 1678],
         [3918, 2179], [4061, 2370], [3780, 2212], [3676, 2578], [4029, 2838], [4263, 2931], [3429, 1908], [3507, 2367],
         [3394, 2643], [3439, 3201], [2935, 3240], [3140, 3550], [2545, 2357], [2778, 2826], [2370, 2975]]
# 存储两个城市之间的距离
d = [[0 for i in range(31)] for j in range(31)]
# 存储一条路径
ans = []

# 计算降温次数
cnt = 0


# 计算两个城市之间的距离
def get_city_distance():
    for i in range(len(citys)):
        for j in range(i, len(citys)):
            d[i][j] = d[j][i] = math.sqrt((citys[i][0] - citys[j][0]) ** 2 + (citys[i][1] - citys[j][1]) ** 2)


# 使用随机交换路径中两个城市的位置来产生一条新路径
def create_new(a):
    #a=list(range(len(a)))
    i = random.randint(0, len(a) - 1)
    j = random.randint(0, len(a) - 1)
    a = list(a)
    a[i], a[j] = a[j], a[i]
    return a


# 获取路径的长度
def get_route_distance(a):
    dist = 0
    for i in range(len(a) - 1):
        dist += d[a[i]][a[i + 1]]
    return dist

#模拟退火
def saa():
    # ********** Begin **********#
    get_city_distance()
    cnt = 0
    ans = range(0, len(citys))
    t = T
    result = 0
    while t >= T_end:
        for i in range(0, L):
            ans_new = create_new(ans)
            d1, d2 = get_route_distance(ans), get_route_distance(ans_new)
            de = d2 - d1
            result = d1
            if de<0:
                ans = ans_new
                result = d2
            else:
                if(math.e**(-de/T) > random.random()):
                    ans = ans_new
                    result = d2
        t = t * delta
        cnt+=1   
    # ********** End **********#
    #函数返回三个参数
    #ans:路径,例如:[14, 13, 19, 18, 15, 12, 9, 28, 7, 17, 27, 11, 26, 20, 6, 16, 30, 2, 21, 25, 22, 8, 0, 10, 29, 4, 5, 23, 3, 1, 24]
    #result:路径长度
    #cnt:降温次数
    #路径长度在50000以内即可,降温次数最终返回值应为1448
    return ans,result,cnt

# 第2关:遗传算法

import numpy as np
import math
import random
import time

start = time.time()

# 31个城市的坐标
city_condition=[[106.54,29.59],[ 91.11,29.97],[ 87.68,43.77],[106.27,38.47],[111.65,40.82],
 [108.33,22.84],[126.63,45.75],[125.35,43.88],[123.38,41.8 ],[114.48,38.03],[112.53,37.87],
 [101.74,36.56],[117.0,36.65],[113.6,34.76],[118.78,32.04],[117.27,31.86],
 [120.19,30.26],[119.3,26.08],[115.89,28.68],[113.0,28.21],[114.31,30.52],
 [113.23,23.16],[121.5,25.05],[110.35,20.02],[103.73,36.03],[108.95,34.27],
 [104.06,30.67],[106.71,26.57],[102.73,25.04],[114.1,22.2 ],[113.33,22.13]]

# 距离矩阵
city_count = 31
Distance = np.zeros([city_count, city_count])
for i in range(city_count):
    for j in range(city_count):
        Distance[i][j] = math.sqrt(
            (city_condition[i][0] - city_condition[j][0]) ** 2 + (city_condition[i][1] - city_condition[j][1]) ** 2)
# 种群数
count = 200
# 改良次数
improve_count = 500
# 进化次数
iteration = 200
# 设置强者的定义概率,即种群前20%为强者
retain_rate = 0.2
# 变异率
mutation_rate = 0.1
# 设置起点
index = [i for i in range(city_count)]

#总距离
def get_total_distance(path_new):
    distance = 0
    for i in range(city_count - 1):
        # count为30,意味着回到了开始的点,此时的值应该为0.
        distance += Distance[int(path_new[i])][int(path_new[i + 1])]
    distance += Distance[int(path_new[-1])][int(path_new[0])]
    return distance

# 改良
#思想:随机生成两个城市,任意交换两个城市的位置,如果总距离减少,就改变染色体。
def improve(x):
    i = 0
    distance = get_total_distance(x)
    while i < improve_count:
        u = random.randint(0, len(x) - 1)
        v = random.randint(0, len(x) - 1)
        if u != v:
            new_x = x.copy()
            ## 随机交叉两个点,t为中间数
            t = new_x[u]
            new_x[u] = new_x[v]
            new_x[v] = t
            new_distance = get_total_distance(new_x)
            if new_distance < distance:
                distance = new_distance
                x = new_x.copy()
        else:
            continue
        i += 1

# 适应度评估,选择,迭代一次选择一次
def selection(population):
    # 对总距离从小到大进行排序
    graded = [[get_total_distance(x), x] for x in population]
    graded = [x[1] for x in sorted(graded)]
    # 选出适应性强的染色体
    # ********** Begin **********#
    retain_length = int(len(graded) * retain_rate)
    # ********** End **********#
    #适应度强的集合,直接加入选择中
    # ********** Begin **********#
    parents = graded[:retain_length]
    # ********** End **********#
    ## 轮盘赌算法选出K个适应性不强的个体,保证种群的多样性
    s = graded[retain_length:]
    # 挑选的不强的个数
    k = count * 0.2
    # 存储适应度
    a = []
    for i in range(0, len(s)):
        a.append(get_total_distance(s[i]))
    sum = np.sum(a)
    b = np.cumsum(a / sum)
    while k > 0:  # 迭代一次选择k条染色体
        t = random.random()
        for h in range(1, len(b)):
            if b[h - 1] < t <= b[h]:
                parents.append(s[h])
                k -= 1
                break
    return parents

# 交叉繁殖
def crossover(parents):
    # 生成子代的个数,以此保证种群稳定
    target_count = count - len(parents)
    # 孩子列表
    children = []
    while len(children) < target_count:
        male_index = random.randint(0, len(parents) - 1)
        female_index = random.randint(0, len(parents) - 1)
        #在适应度强的中间选择父母染色体
        if male_index != female_index:
            male = parents[male_index]
            female = parents[female_index]

            left = random.randint(0, len(male) - 2)
            right = random.randint(left + 1, len(male) - 1)

            # 交叉片段
            gene1 = male[left:right]
            gene2 = female[left:right]

            #得到原序列通过改变序列的染色体,并复制出来备用。
            child1_c = male[right:] + male[:right]
            child2_c = female[right:] + female[:right]
            child1 = child1_c.copy()
            child2 = child2_c.copy()

            #已经改变的序列=>去掉交叉片段后的序列
            for o in gene2:
                child1_c.remove(o)
            for o in gene1:
                child2_c.remove(o)

            #交换交叉片段
            # ********** Begin **********#
            child1[left:right] = gene2
            child2[left:right] = gene1

            child1[right:] = child1_c[0:len(child1) -right]
            child1[:left] = child1_c[len(child1) -right:]

            child2[right:] = child2_c[0:len(child1) -right]
            child2[:left] = child2_c[len(child1) -right:]

            children.append(child1)
            children.append(child2)
            # ********** End **********#

    return children

# 变异
def mutation(children):
    #children现在包括交叉和优质的染色体
    for i in range(len(children)):
        if random.random() < mutation_rate:
            child = children[i]
            #产生随机数
            u = random.randint(0, len(child) - 4)
            v = random.randint(u + 1, len(child) - 3)
            w = random.randint(v + 1, len(child) - 2)
            child = child[0:u] + child[v:w] + child[u:v] + child[w:]
            children[i] = child
    return children


# 得到最佳纯输出结果
def get_result(population):
    graded = [[get_total_distance(x), x] for x in population]
    graded = sorted(graded)
    return graded[0][0], graded[0][1]

# 第3关:蚁群算法

import numpy as np
import math
import random
import time
 
# 31个城市的坐标
city_condition=[[106.54,29.59],[ 91.11,29.97],[ 87.68,43.77],[106.27,38.47],[111.65,40.82],
 [108.33,22.84],[126.63,45.75],[125.35,43.88],[123.38,41.8 ],[114.48,38.03],[112.53,37.87],
 [101.74,36.56],[117.0,36.65],[113.6,34.76],[118.78,32.04],[117.27,31.86],
 [120.19,30.26],[119.3,26.08],[115.89,28.68],[113.0,28.21],[114.31,30.52],
 [113.23,23.16],[121.5,25.05],[110.35,20.02],[103.73,36.03],[108.95,34.27],
 [104.06,30.67],[106.71,26.57],[102.73,25.04],[114.1,22.2 ],[113.33,22.13]]
 
"""
距离矩阵和总距离的计算
"""
#距离矩阵
city_count = 31
Distance = np.zeros((city_count, city_count))
for i in range(city_count):
    for j in range(city_count):
        if i != j:
            Distance[i][j] = math.sqrt((city_condition[i][0] - city_condition[j][0]) ** 2 + (city_condition[i][1] - city_condition[j][1]) ** 2)
        else:
            Distance[i][j] = 100000
 
#适应度计算
def get_total_distance(path_new):
    distance = 0
    # ********** Begin **********#
    for i in range(city_count):
        if i == city_count - 1:  # 最后一个城市回到起点
            distance += Distance[path_new[i]][path_new[0]]
        else:
            distance += Distance[path_new[i]][path_new[i + 1]]
    return distance
    # ********** End **********#
    return distance
"""
两个难点
1.城市的选择:初始城市选择和下一个城市的选择设计
2.信息素的更新
"""
def main():
    ##参数设计
    # 蚂蚁数量
    AntCount = 10
    # 城市数量
    city_count = 31
    # 信息素
    alpha = 1  # 信息素重要程度因子
    beta = 5  # 启发函数重要程度因子
    rho = 0.1 #挥发速度
    iter = 0  # 迭代初始值
    iteration = 200  # 最大迭代值
    Q = 1
    # 初始信息素矩阵,全是为1组成的矩阵
    pheromonetable = np.ones((city_count, city_count))
    # print(pheromonetable)
    # 候选集列表
    candidate = np.zeros((AntCount, city_count)).astype(int)  # 存放100只蚂蚁的路径(一只蚂蚁一个路径),一共就Antcount个路径,一共是蚂蚁数量*31个城市数量
    path_best = np.zeros((iteration, city_count))  # path_best存放的是相应的,每次迭代后的最优路径,每次迭代只有一个值
    # 存放每次迭代的最优距离
    distance_best = np.zeros(iteration)
    #怎么处理对角线的元素是0的情况
    etable = 1.0 / Distance  # 倒数矩阵
 
    while iter < iteration:
        """
        #路径创建
        """
        ## first:蚂蚁初始点选择
        # ********** Begin **********#
        start_cities = random.choices(range(city_count), k=AntCount)  # 随机选择蚂蚁的起始城市
        candidate[:, 0] = start_cities  # 将每个蚂蚁的起始城市记录在候选集列表中
        # ********** End **********#
 
        ## second:选择下一个城市选择
        length = np.zeros(AntCount)
        for i in range(AntCount):
            # 移除已经访问的第一个元素
            unvisit = list(range(city_count))  # 列表形式存储没有访问的城市编号
            visit = candidate[i, 0]  # 当前所在点,第i个蚂蚁在第一个城市
            unvisit.remove(visit)  # 在未访问的城市中移除当前开始的点
            for j in range(1, city_count):#访问剩下的city_count个城市,city_count次访问
                protrans = np.zeros(len(unvisit))#每次循环都更改当前没有访问的城市的转移概率矩阵1*30,1*29,1*28...
                # 下一城市的概率函数
                for k in range(len(unvisit)):
                    # 计算当前城市到剩余城市的(信息素浓度^alpha)*(城市适应度的倒数)^beta
                    # etable[visit][unvisit[k]],(alpha+1)是倒数分之一,pheromonetable[visit][unvisit[k]]是从本城市到k城市的信息素
                    # ********** Begin**********#
                    protrans[k] = (pheromonetable[visit][unvisit[k]] ** alpha) * (etable[visit][unvisit[k]] ** beta)
                    # ********** End **********#
                # 累计概率,轮盘赌选择
                cumsumprobtrans = (protrans / sum(protrans)).cumsum()
                cumsumprobtrans -= np.random.rand()
                # 求出离随机数产生最近的索引值
                k = unvisit[list(cumsumprobtrans > 0).index(True)]
                # 下一个访问城市的索引值
                candidate[i, j] = k
                unvisit.remove(k)
                length[i] += Distance[visit][k]
                visit = k  # 更改出发点,继续选择下一个到达点
            length[i] += Distance[visit][candidate[i, 0]]#最后一个城市和第一个城市的距离值也要加进去
        """
        更新路径等参数
        """
        # 如果迭代次数为一次,那么无条件让初始值代替path_best,distance_best.
        if iter == 0:
            distance_best[iter] = length.min()
            path_best[iter] = candidate[length.argmin()].copy()
        else:
            # 如果当前的解没有之前的解好,那么当前最优还是为之前的那个值;并且用前一个路径替换为当前的最优路径
            if length.min() > distance_best[iter - 1]:
                distance_best[iter] = distance_best[iter - 1]
                path_best[iter] = path_best[iter - 1].copy()
            else:  # 当前解比之前的要好,替换当前解和路径
                distance_best[iter] = length.min()
                path_best[iter] = candidate[length.argmin()].copy()
 
        """
            信息素的更新
        """
        #信息素的增加量矩阵
 
        changepheromonetable = np.zeros((city_count, city_count))
        for i in range(AntCount):
            for j in range(city_count - 1):
                # 当前路径比如城市23之间的信息素的增量:1/当前蚂蚁行走的总距离的信息素
                # ********** Begin **********#
                changepheromonetable[candidate[i, j]][candidate[i, j + 1]] += Q / length[i]
                # ********** End **********#
            #最后一个城市和第一个城市的信息素增加量
            changepheromonetable[candidate[i, j + 1]][candidate[i, 0]] += Q / length[i]
        #信息素更新的公式:
 
        # ********** Begin **********#
        pheromonetable *= (1 - rho)  # 先挥发
        for i in range(AntCount):
            for j in range(city_count - 1):
                pheromonetable[candidate[i, j]][candidate[i, j + 1]] += changepheromonetable[candidate[i, j]][candidate[i, j + 1]]
            pheromonetable[candidate[i, city_count - 1]][candidate[i, 0]] += changepheromonetable[candidate[i, city_count - 1]][candidate[i, 0]]
        # ********** End **********#
        iter += 1
    return distance_best,path_best,iteration

# 第4关:粒子群算法

"""
1.速度更新公式
new_v = w*v + c1 * rand() * (pbest - position) + c2 * rand() * (gbest-position)

    v为粒子当前的速度,w为惯性因子(有速度就有运动惯性)。rand()为随机数生成函数,能够生成0-1之间的随机数。
    position为粒子当前的位置,pbest为本粒子历史上最好的位置,gbest为种群中所有粒子中当前最好的位置。c1和c2表示学习因子
    分别向本粒子历史最好位置和种群中当前最好位置进行学习。
2.位置更新公式
new_position = position + new_v * t
"""
import random
import time
import numpy as np

# 初始参数设置
# 惯性权重
w = 0.6
# 学习因子
c1 = c2 = 1
# 空间维度
n = 1
# 粒子群数量
N = 20
# 迭代次数
iteration = 100

k0 = -10
k1 = 10

# 适应度函数设计
def get_fitness(x):
    return x + 10 * np.sin(5 * x) + 7 * np.cos(4 * x)

# 第一次种群初始化
def getinitialPopulation(N):
    """
    :param populationSize:种群规模
    :return:
    """
    chromsomes = []
    for popusize in range(N):
        a = random.uniform(k0, k1)
        chromsomes.append(a)
    return chromsomes

# 初始速度的分配
def getinitialV(P):
    velocity0 = []
    for v in range(0, N):
        aa = 0
        velocity0.append(aa)
    return velocity0

# 更新(迭代的开始)
def updateV(v,P,gbest,pbest):
    for i in range(0,N):
        v[i] = w * v[i] + c1 * np.random.random() * (pbest[i]- P[i]) + c2 * np.random.random() * (gbest - P[i])
        P[i] = P[i] + v[i]

    # 边界控制
    for i in range(N):
        if P[i] < k0:
            P[i] = k0
        elif P[i]> k1:
            P[i] = k1

    ## 最优pbest
    # ********** Begin **********#
    for i in range(N):
        if get_fitness(P[i]) < get_fitness(pbest[i]):
            pbest[i] = P[i]
    # ********** End **********#
    return v, P

## 全局最优的寻找
def g_best(P,gbest,globalBestCost):
    # 在各个局部最优中找到全局最优
    # ********** Begin **********#
    for i in range(N):
        if get_fitness(P[i]) < get_fitness(gbest):
            gbest = P[i]
    globalBestCost.append(get_fitness(gbest))
    # ********** End **********#
    return gbest, globalBestCost

##主函数的设计
def main():
    ## 种群的初始化
    P = getinitialPopulation(N)
    gbest = 0
    pbest = P.copy()

    # v的初始化
    velocity = getinitialV(P)
    # 迭代计数器
    iter = 0
    iteration = 50
    # 全局最优值的存储
    globalBestCost = []
    globalBestCost.append(get_fitness(gbest))
    while iter < iteration:
        ## 种群的更新
        velocity, P = updateV(velocity, P, gbest, pbest)
        gbest, globalBestCost = g_best(P, gbest, globalBestCost)
        ### 更新种群中的当前最优和全局最优
        iter = iter + 1
    return iter,gbest,globalBestCost[-1]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值