GA-基因遺傳算法:f(x)=1-x^2

  • GA-基因遺傳算法:求解函數…
    # encoding=utf-8
    
    """
    求解函數Max f(x)=1-x^2 在區間[-1,1]的最大值。
    
    在[-1,1]的刻度區間內,若是要精確到0.001,也就是說我們的刻度最小量度要小於0.001。
    區間需要等分爲:1-(-1)/0.0001=2000,所以我們需要11位的二進制去表示這些的可能解!
    """
    
    
    """"
    思路:
    首先是需要一個實體,承載對應的方法->類.
    
    類變量:
        種羣大小:種羣個體集合大小.
        種羣基因:染色體長度,個人基因集合.
    
    類方法:
        初始種羣生成函數:
            個體染色體生成函數
            種羣列表締造函數
        進化函數:
            選擇函數
            交叉函數
            變異函數
            染色體變換函數:基因/染色體<-->表徵|編碼<-->解碼.
        評估函數
    
    
    """
    import random
    
    
    class GA():
        # 對象初始化參數:染色體位數 個體數量.
        def __init__(self, length, count):
            # 染色體長度
            self.length = length
            # 種羣中的染色體數量
            self.count = count
            # 隨機生成初始種羣
            self.population = self.gen_population(length, count)
    
        # 演化函數:保留 選擇 突變.
        def evolve(self, retain_rate=0.2, random_select_rate=0.5, mutation_rate=0.01):
            """
            進化
            對當前一代種羣依次進行選擇、交叉並生成新一代種羣,然後對新一代種羣進行變異.
            """
            parents = self.selection(retain_rate, random_select_rate)
            self.crossover(parents)
            self.mutation(mutation_rate)
    
        def gen_chromosome(self, length):
            """
            隨機生成長度爲length的染色體,每個基因的取值是0或1.
            這裏用一個bit表示一個基因
            返回基因的十進制致表達,最大爲2^(length-1)!
            """
            chromosome = 0
            # [0,1...length-1]
            for i in range(length):
                chromosome |= (1 << i) * random.randint(0, 1)
            return chromosome
    
        def gen_population(self, length, count):
            """
            獲取初始種羣(一個含有count個長度爲length的染色體的列表)
            """
            return [self.gen_chromosome(length) for i in range(count)]
    
        def fitness(self, chromosome):
            """
            計算適應度,將染色體解碼爲[-1,1]之間數字,代入函數計算
            因爲是求最大值,所以數值越大,適應度越高
            """
            x = self.decode(chromosome)
            return 1 - (x * x)
    
        def selection(self, retain_rate, random_select_rate):
            """
            選擇
            先對適應度從大到小排序,選出存活的染色體.
            再進行隨機選擇,選出適應度雖然小,但是倖存下來的個體.
            """
            # 對適應度從大到小進行排序.
            graded = [(self.fitness(get_chromosome), get_chromosome) for get_chromosome in self.population]
            # print(graded)
            graded = [x[1] for x in sorted(graded, reverse=True)]
            # 選出適應性強的染色體
            retain_length = int(len(graded) * retain_rate)
            parents = graded[:retain_length]
            # 選出適應性不強,但是倖存的染色體
            for chromosome in graded[retain_length:]:
                if random.random() < random_select_rate:
                    parents.append(chromosome)
            return parents
    
        def crossover(self, parents):
            """
            染色體的交叉、繁殖,生成新一代的種羣
            """
            # 新出生的孩子,最終會被加入存活下來的父母之中,形成新一代的種羣。
            children = []
            # 需要繁殖的孩子的量
            target_count = len(self.population) - len(parents)
            # 開始根據需要的量進行繁殖
            while len(children) < target_count:
                male = random.randint(0, len(parents) - 1)
                female = random.randint(0, len(parents) - 1)
                if male != female:
                    # 隨機選取交叉點
                    cross_pos = random.randint(0, self.length)
                    # 生成掩碼,方便位操作
                    mask = 0
                    for i in range(cross_pos):
                        mask |= (1 << i)
                    male = parents[male]
                    female = parents[female]
                    # 孩子將獲得父親在交叉點前的基因和母親在交叉點後(包括交叉點)的基因
                    child = ((male & mask) | (female & ~mask)) & ((1 << self.length) - 1)
                    children.append(child)
            # 經過繁殖後,孩子和父母的數量與原始種羣數量相等,在這裏可以更新種羣。
            self.population = parents + children
    
        def mutation(self, rate):
            """
            變異
            對種羣中的所有個體,隨機改變某個個體中的某個基因
            """
            for i in range(len(self.population)):
                if random.random() < rate:
                    j = random.randint(0, self.length - 1)
                    self.population[i] ^= 1 << j
    
        def decode(self, chromosome):
            """
            解碼染色體,將二進制轉化爲屬於[-1, 1]的實數
            """
            return chromosome * 2 / ((2 ** self.length) - 1) - 1
    
        def result(self):
            """
            獲得當前代的最優值,這裏取的是函數取最大值時x的值。
            """
            graded = [(self.fitness(chromosome), chromosome) for chromosome in self.population]
            graded = [x[1] for x in sorted(graded, reverse=True)]
            return ga.decode(graded[0])
    
    
    if __name__ == '__main__':
        # 染色體長度爲11, 種羣數量爲500
        ga = GA(11, 500)
    
        # 1000次進化迭代
        for x in range(1000):
            ga.evolve()
        # 此時顯示的是當前代最大值時候,x的取值!
        print("x = {:.8f},  f(x):1-x^2 = {:.8f}".format(ga.result(), 1 - ga.result() ** 2))
    
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章