Algoritmo de colonia de hormigas de la serie de algoritmos inteligentes (versión complementaria detallada)

inserte la descripción de la imagen aquí

  La portada de este blog ChatGPT + DALL·E 2fue en coautoría.

prefacio

  Este artículo es el sexto artículo de la columna Algoritmo inteligente (reproducción de Python) , que es principalmente un complemento del algoritmo de colonia de hormigas.
  En el blog anterior, se presentó brevemente el principio del algoritmo de colonia de hormigas y pythonse realizó la aplicación del algoritmo de colonia de hormigas para encontrar el valor extremo de la función, pero después de un estudio cuidadoso, se descubrió que los puntos clave no estaban resaltados. , y era diferente de TSPla colonia de hormigas en el problema original. El algoritmo es bastante diferente, y se siente que solo involucra el caparazón del algoritmo de la colonia de hormigas, y no toca el alma.
  Por lo tanto, en este artículo, se hace un complemento detallado a la aplicación del algoritmo de colonia de hormigas para encontrar el valor extremo de la función, y se toca el alma del algoritmo de colonia de hormigas tanto como sea posible.

  Referencia en papel: Aplicación del algoritmo de colonia de hormigas para resolver todos los valores extremos de una función ( HowNet )

1. Método de mejora

  Sea la función unidimensional y = f ( x ) y=f(x)y=El dominio de f ( x ) es [ a , b ] [a, b][ un ,b ] .
  (1)el intervalo[ a , b ] [a, b][ un ,b ] se divide en varios subintervalos de igual longitud, estos subintervalos se registran como{ I 1 , I 2 , . . . , I n } \{I_1,I_2,...,I_n\}{ yo1,I2,... ,In} , intervaloI i I_iIyoEl punto medio de xi se denota como x_iXyo;
  (2)Sea e intervalo I i I_iIyoEl intervalo adyacente es I i + 1 I_{i+1}Iyo + 1, yo yo yo_yoIyoSuma yo i + 1 I_{i+1}Iyo + 1Hay un borde virtual e entre ( I i + 1 , I i + 1 ) e(I_{i+1}, I_{i+1})e ( yoyo + 1,Iyo + 1) , el peso de la arista (distancia virtual) yf ( xi ) − f ( xi + 1 ) f(x_i) - f(x_{i+1})f ( xyo)f ( xyo + 1) ,f ( xi ) − f ( xi + 1 ) f(x_i) - f(x_{i+1})f ( xyo)f ( xyo + 1) es más grande, la hormiga del intervaloI i I_iIyoCambiar al intervalo I i + 1 I_{i+1}Iyo + 1Cuanto mayor sea la posibilidad,
  (3)la hormiga del intervalo I i I_iIyoCambiar al intervalo I i + 1 I_{i+1}Iyo + 1Finalmente, para dejar la feromona, el tamaño de la feromona que queda es el mismo que f ( xi ) − f ( xi + 1 ) f(x_i) - f(x_{i+1})f ( xyo)f ( xyo + 1) cantidad relacionada, intervaloI i + 1 I_{i+1}Iyo + 1Cuantas más feromonas hay, más hormigas en los intervalos adyacentes son atraídas para transferirse a él;
  (4)después de que las hormigas se hayan transferido muchas veces, algunos intervalos contienen muchas hormigas, mientras que otros intervalos no contienen hormigas. Los intervalos que contienen hormigas son exactamente los intervalos que contienen puntos extremos, y es poco probable que los intervalos sin hormigas contengan puntos extremos;
  (5)elimine los intervalos que contienen hormigas y refínelos nuevamente, repita el proceso de búsqueda anterior hasta que el intervalo de refinamiento sea lo suficientemente pequeño.
  Al final, las hormigas se quedaron cerca del punto extremo, y el punto medio del intervalo donde estaban ubicadas las hormigas era exactamente la posición del punto extremo.

2. Inicialización de la colonia de hormigas

  Primero, el dominio del problema [ a , b ] [a, b][ un ,b ] parannn división igual, la longitud de cada intervalo después de la división igual es σ = b − an \sigma = \frac {ba} {n}pag=nortebunCada intervalo se escribe como { I 1 , I 2 , . . . , In } \{I_1,I_2,...,I_n\}{ yo1,I2,... ,In} , ), dondeyo yo ( yo = 1 , 2 , . . , n ) yo_i(i=1,2,..,n)Iyo( yo=1 ,2 ,.. ,n ) significa laiii个区间,则I i = [ a + ( i − 1 ) σ , a + i σ ] I_i=[a+(i-1)\sigma, a+i\sigma]Iyo=[ un+( yo1 ) pag ,a+] , intervalo de visualizaciónI i I_iIyoLos extremos izquierdo y derecho del intervalo I i I_iIyoLa posición del punto medio de se denota como xi x_iXyo,则xi = a + ( yo − 1 2 ) σ x_i=a+(i-\frac {1} {2})\sigmaXyo=a+( yo21) σ asume que hay un total de mm  en la colonia de hormigasm hormigas, registradas como{ a 1 , a 2 , . . . , an } \{a_1,a_2,...,a_n\}{ un1,a2,... ,an} En general,m ≥ nm \geq nmetronorte _ Al principio, se asigna aleatoriamente un intervalo a cada hormiga y la posición de la hormiga es el punto medio del intervalo. τ yo ( t ) \tau _i(t)tyo( t ) significattSubintervaloii en el tiempo tPara la feromona en i , la concentración de feromona de cada subintervalo es la misma al principio y el valor predeterminado es1.0;Δ τ i ( t ) \Delta \tau _i(t)re _yo( t ) significattSubintervaloii en el tiempo tEl incremento de feromonas en i , el incremento de feromonas inicial de cada subintervalo también es el mismo, el valor predeterminado es0.

3. Estrategia móvil de hormigas

  假设vecino (I i) vecino (I_i)vecina o ( yo _ _ _ _yo) intervalo de visualizaciónI i I_iIyoConjunto de intervalos vecinos, función vecino ( yo yo ) = { { yo yo + 1 } , yo = 1 { yo yo − 1 , yo yo + 1 } , yo = 2 , 3 , . . . , norte − 1 { yo yo − 1 } , i = n vecino(I_i) = \begin{casos} \{I_{i+1}\}, & i=1\\ \{I_{i-1}, I_{ i+1}\ }, & i=2,3,...,n-1\\ \{I_{i-1}\}, & i=n \end{casos}vecina o ( yo _ _ _ _yo)= { yoyo + 1} ,{ yoyo 1,Iyo + 1} ,{ yoyo 1} ,i=1i=2 ,3 ,... ,norte1i=n  en el intervalo yo yo yo_iIyoLas hormigas del intervalo adyacente I j I_jIjtransferir, suponiendo que yo yo yo_iIyoSuma I j I_jIjHay una arista virtual e ( I i , I j ) e(I_i,I_j)e ( yoyo,Ij) , el peso de esta arista es∣ f ( xi ) − f ( xj ) ∣ \bigg| f(x_i) - f(x_j) \bigg| f ( xyo)f ( xj) , entonces la función heurística η ij = ∣ f ( xi ) − f ( xj ) ∣ \eta_{ij} = \bigg| f(x_i) - f(x_j) \bigg|elyo= f ( xyo)f ( xj)   Deja que la hormiga ak a_kakActualmente en el intervalo I i I_iIyo,若f ( xi ) − f ( xj ) > 0 f(x_i) - f(x_j) > 0f ( xyo)f ( xj)>0 , el intervalo antes de mostrarI i I_iIyoEl valor de arriba es mayor, la hormiga ak a_kakse puede transferir a su intervalo adyacente I j I_jIj; De lo contrario, las hormigas no se transferirán a él. Permitir permitidok permitir_kpermitido _ _ _ _ _ksignifica hormiga ak a_kakUna colección de subintervalos que se pueden transferir en el siguiente paso.
  Usa pijk ( t ) p_{ij}^k(t)pagyok( t ) significa eltttht ciclo hormigaak a_kakDe la sección infantil I i I_iIyoTransferir al subintervalo I j I_jIjLa probabilidad de imitar el algoritmo básico de la colonia de hormigas, definiendo ant ak a_kakDerive las funciones: pijk ( t ) = { τ j α ( t ) η ij β ∑ h ∈ permitidok τ j α ( t ) η ih β , j ∈ permitidok 0 , j ∉ permitidok p_{ij}^k(t) . ) = \begin{casos}\frac {\tau_j^{\alpha}(t) \\eta_{ij}^{\beta}} {\sum_{h\in permitido_k} \tau_j^{\alpha}( t ) \\eta_{ih}^{\beta}}, &j \en permitido_k\\\\0, &j \no en permitido_k\end{casos}pagyok( t )= h a l o w e dktja( t ) h yobtja( t ) h yob,0 ,jpermitido _ _ _ _ _kj/permitido _ _ _ _ _k  Entre ellos, α \alphaα es el factor heurístico de información (factor de importancia de feromonas),β \betaβ es el factor heurístico esperado (factor de importancia de la función heurística),τ j \tau _jtjIntervalo de Toshi I i {I_i}Iyoconcentración de feromonas.

4. Actualización de feromonas

  si hormiga ak a_kakDel subintervalo I i I_i según probabilidadIyotransferido al subintervalo I j I_jIj, entonces la hormiga ak a_kakDejará feromona en el intervalo, y la cantidad de feromona que queda se expresa mediante Δ τ jk ( t ) \Delta \tau_j^{k}(t)re _jk( t )表示,则Δ τ jk ( t ) = C ( f ( xi ) − f ( xj ) ) \Delta \tau_j^{k}(t) = C\bigg( f(x_i) - f(x_j) \grande)re _jk( t )=C ( f ( xyo)f ( xj) )   Entre ellos,CCC representa una constante,f ( xi ) − f ( xj ) f(x_i) - f(x_j)f ( xyo)f ( xj) es más grande, significa hormigaak a_kakCuanta más feromona queda, más atrae a otras hormigas al intervalo I j I_jIjtransferir.
  Todas las transferencias al intervalo I j I_jIjLas hormigas de todas deben dejar las feromonas correspondientes, suponiendo que en ttt ciclos, conbbb hormigas movidas al intervaloI j I_jIj, entonces este bbb las hormigas están en el intervaloI j I_jIjLa suma de las feromonas que quedan es Δ τ j ( t ) = ∑ c = 1 b Δ τ jc ( t ) \Delta \tau_j(t) = \sum_{c=1} ^{b} \Delta \tau_j^{ Connecticut)re _j( t )=c = 1segundore _jdo( t )   Después de que todas las hormigas completen una transferencia de intervalo vecina, necesitan actualizar la feromona
. IntervaloI j I_jIjLa concentración de feromonas de τ j \tau_jtj手机的τ j ( t + 1 ) = ( 1 − 1 ρ ) τ j ( t ) + Δ τ j ( t ) \tau_j(t+1) = (1-1\rho)\tau_j(t) + \ Delta \tau_j(t)tj( t+1 )=( 11 r ) tj( t )+re _j( t )   donde,ρ \rhoρ representa el coeficiente de volatilización de feromonas.

5. Reducción del espacio de búsqueda de la colonia de hormigas.

  El intervalo con un valor de función más pequeño contendrá más feromona, lo que es más probable que atraiga a las hormigas para que se transfieran a él. Después de algunos ciclos, cuando todas las hormigas dejen de transferirse, la distribución de la colonia de hormigas tendrá tales características: todas las hormigas se distribuyen en el intervalo con puntos extremos más pequeños, mientras que no hay hormigas en otros intervalos, es decir, el intervalo que contiene hormigas contiene extremo puntos punto de valor pequeño.
  Elimine estos intervalos que contienen hormigas, refine estos intervalos nuevamente y deje que la colonia de hormigas busque el punto mínimo en estos intervalos en el próximo ciclo. Si este ciclo continúa, el rango de búsqueda de la colonia de hormigas se hará cada vez más pequeño. Cuando el intervalo refinado es lo suficientemente pequeño, todas las hormigas permanecerán cerca del punto extremo, y el punto medio del intervalo donde permanece la hormiga es el punto de valor extremo. ubicación.
  Se establece un umbral en el documento. Después de todo, es imposible subdividir indefinidamente. Cuando el tamaño de paso del intervalo es menor que el umbral, la subdivisión del intervalo se detiene y la búsqueda finaliza. En la implementación de este artículo, no se adopta la operación del artículo, sino que se adopta directamente un pequeño paso de intervalo al principio, de modo que la solución óptima buscada está muy cerca del valor óptimo teórico.

6. Implementación del código

# -*- coding:utf-8 -*-
# Author:   xiayouran
# Email:    [email protected]
# Datetime: 2023/5/6 14:59
# Filename: ant_colony_optimization.py
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

from base_algorithm import BaseAlgorithm


__all__ = ['AntColonyOptimization']


class Ant:
    def __init__(self):
        self.id = None          # 蚂蚁所在区间的id
        self.eta = None         # 启发式信息, 存放本区间与其左右两个区间的函数差值
        self.tran_prob = None   # 状态转移概率


class Interval:
    def __init__(self):
        self.position = None    # 该区间上的中点
        self.tau = 1.           # 信息素浓度值
        self.delta_tau = 0.     # 信息素浓度增量
        self.count = 0          # 此区间上蚂蚁的数量


class AntColonyOptimization(BaseAlgorithm):
    def __init__(self, population_size=100, max_iter=200, alpha=1.5, beta=0.8, rho=0.3, epsilon=1e-4,
                 q=1.0, step=0.01, x_range=(0, 5), seed=10086):
        super(AntColonyOptimization, self).__init__()
        self.__population_size = population_size  # 蚂蚁种群大小
        self.__max_iter = max_iter  # 最大迭代次数
        self.__alpha = alpha        # 信息素重要程度因子
        self.__beta = beta          # 启发函数重要程度因子
        self.__rho = rho            # 信息素蒸发系数
        self.__epsilon = epsilon    # 停止搜索门限
        self.__q = q                # 信息素释放增量系数, 常量C
        self.__step = step          # 子区间间隔
        self.__x_range = x_range    # 变量x的定义域
        self.__population = []      # 蚁群
        self.__interval_set = []    # 区间集合(对应TSP问题中的city)
        self.__tabu = []            # 禁忌表
        self.__seed = seed
        self.optimal_solution = None

        np.random.seed(seed)

    def init_interval_set(self):
        for left_point in np.arange(*self.__x_range, self.__step):
            interval = Interval()
            interval.position = left_point + self.__step / 2  # 区间中点
            self.__interval_set.append(interval)

        if len(self.__interval_set) > self.__population_size:
            tmp_size = self.__population_size
            self.__population_size = int(np.ceil(len(self.__interval_set) / self.__population_size) * self.__population_size)
            print("Suggest a larger value for population_size, the value for population_size has been "
                  "changed from {} to {}".format(tmp_size, self.__population_size))

    def init_tabu(self):
        self.__tabu = np.zeros(shape=(len(self.__interval_set), 2))   # 初始禁忌表, 当前点与左右两坐标
        # TSP中的禁忌表的shape是(m, n), 其中m为蚂蚁数量, n为城市数量, 确保每只蚂蚁仅能访问城市一次

    def update_eta(self, ant):
        index = ant.id
        interval = self.__interval_set[index]
        ant.eta = []

        if index == 0:
            ant.eta.append(0)
            ant.eta.append(self.problem_function(interval.position) - self.problem_function(
                interval.position + self.__step))
        elif index == len(self.__interval_set) - 1:
            ant.eta.append(self.problem_function(interval.position) - self.problem_function(
                interval.position - self.__step))
            ant.eta.append(0)
        else:
            ant.eta.append(self.problem_function(interval.position) - self.problem_function(
                interval.position - self.__step))  # 当前区间(中点)与左邻居区间(中点)的差值
            ant.eta.append(self.problem_function(interval.position) - self.problem_function(
                interval.position + self.__step))  # 当前区间(中点)与右邻居区间(中点)的差值

    def update_tabu(self, ant):
        index = ant.id
        if ant.eta[0] > 0:
            self.__tabu[index, 0] = 1  # 表示左子区间值较小, 可以跳转
        if ant.eta[1] > 0:
            self.__tabu[index, 1] = 1  # 表示右子区间值较小, 可以跳转

    def init_population(self):
        # 初始化区间集合
        self.init_interval_set()

        # 初始化禁忌表
        self.init_tabu()

        for i in range(self.__population_size):
            index = np.random.choice(range(len(self.__interval_set)))   # 随机选择一个区间
            # index = i
            interval = self.__interval_set[index]
            interval.count += 1

            ant = Ant()
            ant.id = index

            # 更新eta
            self.update_eta(ant)

            # 更新禁忌表tabu
            self.update_tabu(ant)

            # 更新蚂蚁的状态转移概率
            ant.tran_prob = interval.tau * ant.eta[0] / (interval.tau * ant.eta[0] + interval.tau * ant.eta[1])  # 蚂蚁向左区间跳转概率

            self.__population.append(ant)

    def skip_left(self, ant):
        index = ant.id

        interval = self.__interval_set[index]
        interval.count -= 1  # 此区间蚂蚁数-1
        left_interval = self.__interval_set[index - 1]
        left_interval.count += 1  # 左区间蚂蚁数+1
        ant.id -= 1  # 蚂蚁跳转至左区间
        left_interval.delta_tau = left_interval.delta_tau + self.__q * ant.eta[0]

    def skip_right(self, ant):
        index = ant.id

        interval = self.__interval_set[index]
        interval.count -= 1  # 此区间蚂蚁数-1
        right_interval = self.__interval_set[index + 1]
        right_interval.count += 1  # 右区间蚂蚁数+1
        ant.id += 1  # 蚂蚁跳转至右区间
        right_interval.delta_tau = right_interval.delta_tau + self.__q * ant.eta[1]

    def search_local_optimal_solution(self):
        flag = np.ones(self.__population_size)
        while np.sum(flag):
            for i, ant in enumerate(self.__population):
                index = ant.id
                if self.__tabu[index, 0] and not self.__tabu[index, 1]:
                    # 蚂蚁可以向左区间跳转
                    self.skip_left(ant)
                elif not self.__tabu[index, 0] and self.__tabu[index, 1]:
                    # 蚂蚁可以向右区间跳转
                    self.skip_right(ant)
                elif self.__tabu[index, 0] and self.__tabu[index, 1]:
                    # 两个区间都可以跳转, 计算一下蚂蚁的状态转移概率
                    if ant.tran_prob > np.random.rand():
                        # 蚂蚁向左区间跳转
                        self.skip_left(ant)
                    else:
                        # 蚂蚁向右区间跳转
                        self.skip_right(ant)
                else:
                    flag[i] = 0     # 表示此蚂蚁不再进行跳转了

                self.update_eta(ant)    # 更新eta
                self.update_tabu(ant)   # 更新禁忌表

            for interval in self.__interval_set:
                # 更新区间上的信息素
                interval.tau = (1 - self.__rho) * interval.tau + interval.delta_tau

    def print_local_optimal_solution(self):
        print('local optimal solution:')
        local_optimal_solution = {
    
    }
        best_point = np.inf
        for ant in self.__population:
            index = ant.id
            if not local_optimal_solution.get(index, ''):
                local_optimal_solution[index] = (self.__interval_set[index].position,
                                                 self.problem_function(self.__interval_set[index].position))
                print(local_optimal_solution[index])
                if best_point > local_optimal_solution[index][1]:
                    best_point = local_optimal_solution[index][1]
                    self.optimal_solution = local_optimal_solution[index]

    def solution(self):
        self.init_population()
        self.search_local_optimal_solution()
        self.print_local_optimal_solution()

        print('the optimal solution is', self.optimal_solution)


if __name__ == "__main__":
	algo = AntColonyOptimization()
	algo.solution()

  El efecto de visualización del algoritmo de colonia de hormigas es el siguiente:

inserte la descripción de la imagen aquí

Repositorio de código: IALib[GitHub]

  El código de este artículo se ha sincronizado con Pythonel almacén exclusivo de la columna [Algoritmo inteligente (Recurrencia)]: Algoritmos en la biblioteca   de tiempo de ejecución de IALib :
IALibACO

git clone [email protected]:xiayouran/IALib.git
cd examples
python main.py -algo aco

Supongo que te gusta

Origin blog.csdn.net/qq_42730750/article/details/130662474
Recomendado
Clasificación