python蚁群算法 路径规划_Python手把手构建蚁群算法(ACO)实现最优化搜索

简介

蚁群算法(Ant Colony Optimization,简称ACO)是由Marco Dorigo于1992年发明的一种启发式算法,是通过模拟蚁群寻找食物的过程发现最短路径的行为。和粒子群算法一样,它也属于群集智能的一种。

算法思想

蚁群觅食过程中,每只蚂蚁在所走过的路径上均会释放出一种信息素,该信息素随时间的推移逐渐挥发。因此,每条路径上的信息素同时存在正负反馈两种机制。

正反馈:蚂蚁每次经过该路径均会释放信息素使得该路径上的信息素浓度增加;

负反馈:每条路径上的信息素随时间推移会逐渐挥发。

由此,我们可以判断,在起点与终点之间,当相同数量的蚂蚁初始同时经过两条不同的路径时,路径上初始信息素的浓度是相同的;不过,当路径越短时,信息素挥发时间也越短,残留信息素浓度也将越高。随后的蚂蚁将根据路径上残留信息素浓度的大小对路径进行选择 — 浓度越高,选择概率越大。最终导致信息素浓度越高的路径上蚂蚁的选择数目越多,而更多的蚂蚁也将同时导致该路径上残留信息素浓度越高(即高者越高,低者越低)。因此,在理想情况下,整个蚁群将逐渐向信息素浓度最高的路径(即最短路径)进行转移。

核心算子

该算法主要是位置x和信息素t的更新:

一、根据初始的信息素计算概率:

二、根据概率计算下一时刻的位置:

三、根据当前信息素更新下一时刻的信息素:

根据这三步形成迭代循环过程。

当然在这里我们不再去求路径问题,将其稍微修改可以计算非线性多元函数。分别将上述的概率公式修改为:

信息素更新公式修改为:

需要注意的是,初始信息素可以用目标函数值代替,直到信息素更新一轮后,使用新的信息素计算概率。

示例

我们还是以一个简单的例子来介绍算法的流程。假设我们需要寻找函数y=x12+x22+x33+x44在[1,30]之间的最大值。我们很容易就知道,当x1=x2=x3=x4=30时,该函数能取到最大值。

构建一个叫ACO的类,这个类包括算法的所有操作方法:

class ACO:

def __init__(self, parameters):

pass

def fitness(self, ind_var):

pass

def update_operator(self, gen, t, t_max):

pass

def main(self):

pass

1

2

3

4

5

6

7

8

9

10

11

12

classACO:

def__init__(self,parameters):

pass

deffitness(self,ind_var):

pass

defupdate_operator(self,gen,t,t_max):

pass

defmain(self):

pass

使用__init__()方法初始化参数,包括自变量可取的最大值,最小值,种群大小,迭代代数;使用fitness()方法作为适应度函数评估该个体的函数值,在这里就是函数y的值;使用update_operator()方法根据概率更新蚁群下一时刻的位置和信息素,挑选出当前代蚁群中最好位置作为历史记录;使用main()方法实现整个算法的循环。

__init__()方法

__init__()方法的代码如下:

def __init__(self, parameters):

# 初始化

self.NGEN = parameters[0] # 迭代的代数

self.pop_size = parameters[1] # 种群大小

self.var_num = len(parameters[2]) # 变量个数

self.bound = [] # 变量的约束范围

self.bound.append(parameters[2])

self.bound.append(parameters[3])

self.pop_x = np.zeros((self.pop_size, self.var_num)) # 所有蚂蚁的位置

self.g_best = np.zeros((1, self.var_num)) # 全局蚂蚁最优的位置

# 初始化第0代初始全局最优解

temp = -1

for i in range(self.pop_size):

for j in range(self.var_num):

self.pop_x[i][j] = np.random.uniform(self.bound[0][j], self.bound[1][j])

fit = self.fitness(self.pop_x[i])

if fit > temp:

self.g_best = self.pop_x[i]

temp = fit

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

def__init__(self,parameters):

# 初始化

self.NGEN=parameters[0]# 迭代的代数

self.pop_size=parameters[1]# 种群大小

self.var_num=len(parameters[2])# 变量个数

self.bound=[]# 变量的约束范围

self.bound.append(parameters[2])

self.bound.append(parameters[3])

self.pop_x=np.zeros((self.pop_size,self.var_num))# 所有蚂蚁的位置

self.g_best=np.zeros((1,self.var_num))# 全局蚂蚁最优的位置

# 初始化第0代初始全局最优解

temp=-1

foriinrange(self.pop_size):

forjinrange(self.var_num):

self.pop_x[i][j]=np.random.uniform(self.bound[0][j],self.bound[1][j])

fit=self.fitness(self.pop_x[i])

iffit>temp:

self.g_best=self.pop_x[i]

temp=fit

初始化方法接受传入的参数,包括最大值,最小值,种群大小和迭代代数。通过这些参数初始化产生一个蚂蚁种群,并记录当前代全局最优位置。

fitness()方法

fitness()方法用来评估该位置的函数值,代码如下:

def fitness(self, ind_var):

x1 = ind_var[0]

x2 = ind_var[1]

x3 = ind_var[2]

x4 = ind_var[3]

y = x1**2 + x2**2 + x3**3 + x4**4

return y

1

2

3

4

5

6

7

deffitness(self,ind_var):

x1=ind_var[0]

x2=ind_var[1]

x3=ind_var[2]

x4=ind_var[3]

y=x1**2+x2**2+x3**3+x4**4

returny

update_operator()方法

update_operator()方法里包含核心算子,根据概率更新下一时刻的位置和信息素,代码如下:

def update_operator(self, gen, t, t_max):

rou = 0.8 # 信息素挥发系数

Q = 1 # 信息释放总量

lamda = 1 / gen

pi = np.zeros(self.pop_size)

for i in range(self.pop_size):

for j in range(self.var_num):

pi[i] = (t_max - t[i]) / t_max

# 更新位置

if pi[i] < np.random.uniform(0, 1):

self.pop_x[i][j] = self.pop_x[i][j] + np.random.uniform(-1, 1) * lamda

else:

self.pop_x[i][j] = self.pop_x[i][j] + np.random.uniform(-1, 1) * (

self.bound[1][j] - self.bound[0][j]) / 2

# 越界保护

if self.pop_x[i][j] < self.bound[0][j]:

self.pop_x[i][j] = self.bound[0][j]

if self.pop_x[i][j] > self.bound[1][j]:

self.pop_x[i][j] = self.bound[1][j]

# 更新t值

t[i] = (1 - rou) * t[i] + Q * self.fitness(self.pop_x[i])

# 更新全局最优值

if self.fitness(self.pop_x[i]) > self.fitness(self.g_best):

self.g_best = self.pop_x[i]

t_max = np.max(t)

return t_max, t

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

defupdate_operator(self,gen,t,t_max):

rou=0.8# 信息素挥发系数

Q=1# 信息释放总量

lamda=1/gen

pi=np.zeros(self.pop_size)

foriinrange(self.pop_size):

forjinrange(self.var_num):

pi[i]=(t_max-t[i])/t_max

# 更新位置

ifpi[i]

self.pop_x[i][j]=self.pop_x[i][j]+np.random.uniform(-1,1)*lamda

else:

self.pop_x[i][j]=self.pop_x[i][j]+np.random.uniform(-1,1)*(

self.bound[1][j]-self.bound[0][j])/2

# 越界保护

ifself.pop_x[i][j]

self.pop_x[i][j]=self.bound[0][j]

ifself.pop_x[i][j]>self.bound[1][j]:

self.pop_x[i][j]=self.bound[1][j]

# 更新t值

t[i]=(1-rou)*t[i]+Q*self.fitness(self.pop_x[i])

# 更新全局最优值

ifself.fitness(self.pop_x[i])>self.fitness(self.g_best):

self.g_best=self.pop_x[i]

t_max=np.max(t)

returnt_max,t

需要注意的是,在更新位置的过程中有可能超过了我们定义的定义域范围,因此需要进行越界保护,强行将位置拉进定义域内,最后更新全局最好位置。

main()方法

ACO算法所有的轮子都写好后,我们接下来将它们整合到流程中。代码实现如下:

def main(self):

popobj = []

best = np.zeros((1, self.var_num))[0]

for gen in range(1, self.NGEN + 1):

if gen == 1:

tmax, t = self.update_operator(gen, np.array(list(map(self.fitness, self.pop_x))),

np.max(np.array(list(map(self.fitness, self.pop_x)))))

else:

tmax, t = self.update_operator(gen, t, tmax)

popobj.append(self.fitness(self.g_best))

print('############ Generation {} ############'.format(str(gen)))

print(self.g_best)

print(self.fitness(self.g_best))

if self.fitness(self.g_best) > self.fitness(best):

best = self.g_best.copy()

print('最好的位置:{}'.format(best))

print('最大的函数值:{}'.format(self.fitness(best)))

print("---- End of (successful) Searching ----")

plt.figure()

plt.title("Figure1")

plt.xlabel("iterators", size=14)

plt.ylabel("fitness", size=14)

t = [t for t in range(1, self.NGEN + 1)]

plt.plot(t, popobj, color='b', linewidth=2)

plt.show()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

defmain(self):

popobj=[]

best=np.zeros((1,self.var_num))[0]

forgeninrange(1,self.NGEN+1):

ifgen==1:

tmax,t=self.update_operator(gen,np.array(list(map(self.fitness,self.pop_x))),

np.max(np.array(list(map(self.fitness,self.pop_x)))))

else:

tmax,t=self.update_operator(gen,t,tmax)

popobj.append(self.fitness(self.g_best))

print('############ Generation {} ############'.format(str(gen)))

print(self.g_best)

print(self.fitness(self.g_best))

ifself.fitness(self.g_best)>self.fitness(best):

best=self.g_best.copy()

print('最好的位置:{}'.format(best))

print('最大的函数值:{}'.format(self.fitness(best)))

print("---- End of (successful) Searching ----")

plt.figure()

plt.title("Figure1")

plt.xlabel("iterators",size=14)

plt.ylabel("fitness",size=14)

t=[tfortinrange(1,self.NGEN+1)]

plt.plot(t,popobj,color='b',linewidth=2)

plt.show()

传入循环迭代指定代数,输出目前找到的最好的位置和函数值,并画图得到整个迭代过程。

完整代码

import numpy as np

import matplotlib.pyplot as plt

class ACO:

def __init__(self, parameters):

"""

Ant Colony Optimization

parameter: a list type, like [NGEN, pop_size, var_num_min, var_num_max]

"""

# 初始化

self.NGEN = parameters[0] # 迭代的代数

self.pop_size = parameters[1] # 种群大小

self.var_num = len(parameters[2]) # 变量个数

self.bound = [] # 变量的约束范围

self.bound.append(parameters[2])

self.bound.append(parameters[3])

self.pop_x = np.zeros((self.pop_size, self.var_num)) # 所有蚂蚁的位置

self.g_best = np.zeros((1, self.var_num)) # 全局蚂蚁最优的位置

# 初始化第0代初始全局最优解

temp = -1

for i in range(self.pop_size):

for j in range(self.var_num):

self.pop_x[i][j] = np.random.uniform(self.bound[0][j], self.bound[1][j])

fit = self.fitness(self.pop_x[i])

if fit > temp:

self.g_best = self.pop_x[i]

temp = fit

def fitness(self, ind_var):

"""

个体适应值计算

"""

x1 = ind_var[0]

x2 = ind_var[1]

x3 = ind_var[2]

x4 = ind_var[3]

y = x1 ** 2 + x2 ** 2 + x3 ** 3 + x4 ** 4

return y

def update_operator(self, gen, t, t_max):

"""

更新算子:根据概率更新下一时刻的位置

"""

rou = 0.8 # 信息素挥发系数

Q = 1 # 信息释放总量

lamda = 1 / gen

pi = np.zeros(self.pop_size)

for i in range(self.pop_size):

for j in range(self.var_num):

pi[i] = (t_max - t[i]) / t_max

# 更新位置

if pi[i] < np.random.uniform(0, 1):

self.pop_x[i][j] = self.pop_x[i][j] + np.random.uniform(-1, 1) * lamda

else:

self.pop_x[i][j] = self.pop_x[i][j] + np.random.uniform(-1, 1) * (

self.bound[1][j] - self.bound[0][j]) / 2

# 越界保护

if self.pop_x[i][j] < self.bound[0][j]:

self.pop_x[i][j] = self.bound[0][j]

if self.pop_x[i][j] > self.bound[1][j]:

self.pop_x[i][j] = self.bound[1][j]

# 更新t值

t[i] = (1 - rou) * t[i] + Q * self.fitness(self.pop_x[i])

# 更新全局最优值

if self.fitness(self.pop_x[i]) > self.fitness(self.g_best):

self.g_best = self.pop_x[i]

t_max = np.max(t)

return t_max, t

def main(self):

popobj = []

best = np.zeros((1, self.var_num))[0]

for gen in range(1, self.NGEN + 1):

if gen == 1:

tmax, t = self.update_operator(gen, np.array(list(map(self.fitness, self.pop_x))),

np.max(np.array(list(map(self.fitness, self.pop_x)))))

else:

tmax, t = self.update_operator(gen, t, tmax)

popobj.append(self.fitness(self.g_best))

print('############ Generation {} ############'.format(str(gen)))

print(self.g_best)

print(self.fitness(self.g_best))

if self.fitness(self.g_best) > self.fitness(best):

best = self.g_best.copy()

print('最好的位置:{}'.format(best))

print('最大的函数值:{}'.format(self.fitness(best)))

print("---- End of (successful) Searching ----")

plt.figure()

plt.title("Figure1")

plt.xlabel("iterators", size=14)

plt.ylabel("fitness", size=14)

t = [t for t in range(1, self.NGEN + 1)]

plt.plot(t, popobj, color='b', linewidth=2)

plt.show()

if __name__ == '__main__':

NGEN = 100

popsize = 100

low = [1, 1, 1, 1]

up = [30, 30, 30, 30]

parameters = [NGEN, popsize, low, up]

aco = ACO(parameters)

aco.main()

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

importnumpyasnp

importmatplotlib.pyplotasplt

classACO:

def__init__(self,parameters):

"""

Ant Colony Optimization

parameter: a list type, like [NGEN, pop_size, var_num_min, var_num_max]

"""

# 初始化

self.NGEN=parameters[0]# 迭代的代数

self.pop_size=parameters[1]# 种群大小

self.var_num=len(parameters[2])# 变量个数

self.bound=[]# 变量的约束范围

self.bound.append(parameters[2])

self.bound.append(parameters[3])

self.pop_x=np.zeros((self.pop_size,self.var_num))# 所有蚂蚁的位置

self.g_best=np.zeros((1,self.var_num))# 全局蚂蚁最优的位置

# 初始化第0代初始全局最优解

temp=-1

foriinrange(self.pop_size):

forjinrange(self.var_num):

self.pop_x[i][j]=np.random.uniform(self.bound[0][j],self.bound[1][j])

fit=self.fitness(self.pop_x[i])

iffit>temp:

self.g_best=self.pop_x[i]

temp=fit

deffitness(self,ind_var):

"""

个体适应值计算

"""

x1=ind_var[0]

x2=ind_var[1]

x3=ind_var[2]

x4=ind_var[3]

y=x1**2+x2**2+x3**3+x4**4

returny

defupdate_operator(self,gen,t,t_max):

"""

更新算子:根据概率更新下一时刻的位置

"""

rou=0.8# 信息素挥发系数

Q=1# 信息释放总量

lamda=1/gen

pi=np.zeros(self.pop_size)

foriinrange(self.pop_size):

forjinrange(self.var_num):

pi[i]=(t_max-t[i])/t_max

# 更新位置

ifpi[i]

self.pop_x[i][j]=self.pop_x[i][j]+np.random.uniform(-1,1)*lamda

else:

self.pop_x[i][j]=self.pop_x[i][j]+np.random.uniform(-1,1)*(

self.bound[1][j]-self.bound[0][j])/2

# 越界保护

ifself.pop_x[i][j]

self.pop_x[i][j]=self.bound[0][j]

ifself.pop_x[i][j]>self.bound[1][j]:

self.pop_x[i][j]=self.bound[1][j]

# 更新t值

t[i]=(1-rou)*t[i]+Q*self.fitness(self.pop_x[i])

# 更新全局最优值

ifself.fitness(self.pop_x[i])>self.fitness(self.g_best):

self.g_best=self.pop_x[i]

t_max=np.max(t)

returnt_max,t

defmain(self):

popobj=[]

best=np.zeros((1,self.var_num))[0]

forgeninrange(1,self.NGEN+1):

ifgen==1:

tmax,t=self.update_operator(gen,np.array(list(map(self.fitness,self.pop_x))),

np.max(np.array(list(map(self.fitness,self.pop_x)))))

else:

tmax,t=self.update_operator(gen,t,tmax)

popobj.append(self.fitness(self.g_best))

print('############ Generation {} ############'.format(str(gen)))

print(self.g_best)

print(self.fitness(self.g_best))

ifself.fitness(self.g_best)>self.fitness(best):

best=self.g_best.copy()

print('最好的位置:{}'.format(best))

print('最大的函数值:{}'.format(self.fitness(best)))

print("---- End of (successful) Searching ----")

plt.figure()

plt.title("Figure1")

plt.xlabel("iterators",size=14)

plt.ylabel("fitness",size=14)

t=[tfortinrange(1,self.NGEN+1)]

plt.plot(t,popobj,color='b',linewidth=2)

plt.show()

if__name__=='__main__':

NGEN=100

popsize=100

low=[1,1,1,1]

up=[30,30,30,30]

parameters=[NGEN,popsize,low,up]

aco=ACO(parameters)

aco.main()

在if __name__ == "__main__":语句后面,我们设定所有的参数。总共跑NGEN=100代,每代的种群大小为100。

最后得到以下结果:

迭代过程如下:

总结

我们将蚁群算法改成了可以实现非线性函数最优化搜索的方式,该算法的核心就是根据概率更新下一时刻的位置和信息素。与粒子群算法非常相似,所需的参数比遗传算法要少。本文的代码能够快速运用到其他问题中,可供借鉴和参考。至此,四大启发式算法就介绍完毕。

参考文献:

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
写FOC(Field-Oriented Control)算法需要一定的电机控制基础和编程能力。下面是一个简单的步骤来手把手教你写FOC算法: 1. 确定电机参数:首先,你需要收集电机的参数,如电感、电阻和磁极对数等。这些参数将在FOC算法中使用。 2. 进行Park变换:Park变换可以将三向坐标系(abc)转换为直角坐标系(αβ),这样可以更方便地控制电机。根据Clark变换的反向公式,你可以将输入的三相电流转换为αβ坐标系中的两个轴电流。 3. 进行Clarke变换:Clarke变换将直角坐标系(αβ)转换回三向坐标系(abc)。在FOC算法中,你需要将控制产生的αβ轴电流转换为abc轴电流。 4. 计算磁场定向角度:根据电机的旋转角度和磁极对数,你可以计算出电机的磁场定向角度。这个角度将用于生成磁场定向的电压指令。 5. 控制电压生成:根据FOC算法,你需要生成磁场定向的电压指令,以控制电机的转速和转矩。这些电压指令通过反转Park和Clarke变换,转换为abc轴电压指令。 6. 实时计算:在实际应用中,你需要以一定的频率更新FOC算法,并实时计算磁场定向角度和电压指令。 请注意,以上只是FOC算法的一个简单概述。实际上,FOC算法还涉及到闭环控制、速度和位置估算等复杂的技术细节。因此,在实际应用中,你可能需要更深入地学习和理解FOC算法,并根据具体情况进行调整和优化。 引用资料: 前言 三向电机 Clark变换<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [永磁同步电机驱动视频教程_矢量控制_手把手教你写代码_无感FOC_有感FOC_状态观测器_卡尔曼滤波_慧驱动](https://blog.csdn.net/huiqudong/article/details/109865310)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [手把手教你电机FOC控制【一】](https://blog.csdn.net/oXiaoLingTong/article/details/123867530)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值