遺傳算法Python實戰 008.魔術方塊

2021-01-14 蝦神daxialu
寫在前面的話:

魔術方塊就是中國所謂的九宮圖(洛書):

他的特點就是橫豎以及左右對角線的數字加起來都是15

一般來說,只要中間是5,其他的排列都可以通過頭角互換(旋轉和鏡像),比如:

6 7 2 
1 5 9
8 3 4

九宮格非常簡單,就算是迭代,也能很快算出結果,如果要擴展成跟多的魔術方塊,比如44或者乾脆是1010呢?

? ? ? ?
? ? ? ?
? ? ? ?
? ? ? ?

我們通過算法來實現一下看看那

算法實現

首先導入需要的包,本次要用到一個新的方法:

import random,datetime
from bisect import bisect_left
from math import exp

bisect_left是Python內置的一個插入預測方法,他可以找到你需要插入數據所在的位置,功能特別好用,示例如下:

from bisect import bisect_left
a = list(range(10))
print(a)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

#如果將3.6插入到列表a中,會出現在哪個位置。
idx = bisect_left(a,3.6)
print(idx)
# 4

然後初始化一堆參數:

diagonalSize是你方塊的數量,3就表示3*3的方塊

maxAge是本節算法需要著重說明的地方,後面解釋

nSquared 這個方塊表面總共有多少個格子

geneset是你的基因庫,從1開始,到格子數量。

expectedSum是對角線之和的值

geneIndexes是每個基因的索引,與基因庫裡面的基因不同的是,索引從0開始

diagonalSize = 3
maxAge = 50
nSquared = diagonalSize * diagonalSize
geneset = [i for i in range(1, nSquared + 1)]
expectedSum = diagonalSize * (nSquared + 1) / 2
geneIndexes = [i for i in range(0, len(geneset))]

定義一個健壯性的類

class Fitness:
def __init__(self, sumOfDifferences):
self.SumOfDifferences = sumOfDifferences

def __gt__(self, other):
return self.SumOfDifferences < other.SumOfDifferences

def __str__(self):
return "{}".format(self.SumOfDifferences)

下面兩個方法是用於健壯性檢驗的,其中:

def get_sums(genes):
rows = [0 for _ in range(diagonalSize)]
columns = [0 for _ in range(diagonalSize)]
southeastDiagonalSum = 0
northeastDiagonalSum = 0
for row in range(diagonalSize):
for column in range(diagonalSize):
value = genes[row * diagonalSize + column]
rows[row] += value
columns[column] += value
southeastDiagonalSum += genes[row * diagonalSize + row]
northeastDiagonalSum += genes[row * diagonalSize +
(diagonalSize - 1 - row)]
return rows, columns, northeastDiagonalSum, southeastDiagonalSum

def get_fitness(genes):
rows, columns, northeastDiagonalSum, southeastDiagonalSum = \
get_sums(genes)

sumOfDifferences = sum(int(abs(s - expectedSum))
for s in rows + columns +
[southeastDiagonalSum, northeastDiagonalSum]
if s != expectedSum)

return Fitness(sumOfDifferences)

顯示方法:解釋略,除了顯示當前方塊的情況以外,還能夠列印出行列對角線的和。

def display(candidate, startTime):
timeDiff = datetime.datetime.now() - startTime

rows, columns, northeastDiagonalSum, southeastDiagonalSum = \
get_sums(candidate.Genes)

for rowNumber in range(diagonalSize):
row = candidate.Genes[
rowNumber * diagonalSize:(rowNumber + 1) * diagonalSize]
print("\t ", row, "=", rows[rowNumber])
print(northeastDiagonalSum, "\t", columns, "\t", southeastDiagonalSum)
print(" - - - - - - - - - - -", candidate.Fitness, timeDiff)

進化方法:本節的進化方法又回到了最簡單的狀態,直接隨機交換兩個基因,完成進化

def mutate(chm):
genes = chm.Genes[:]
indexA, indexB = random.sample(geneIndexes,2)
genes[indexA], genes[indexB] = genes[indexB], genes[indexA]
return Chromosome(genes, get_fitness(genes))

種群類,多了一個成員變量Age——它的用途稍後解釋

class Chromosome:
def __init__(self, genes, fitness):
self.Genes = genes
self.Fitness = fitness
self.Age = 0

本節算法的核心方法,進化過程這也是到現在為止,最複雜的進化方法,見代碼中的注釋:

#初始化初代種群的方法
def fnCustomCreate():
gens = random.sample(geneset, len(geneset))
ch1 = Chromosome(gens, get_fitness(gens))
return ch1

# 這是一個內部方法,用來不斷生成進化種群
# 裡面使用是Python特有的yield方法,用於返回生成的種群
# yield的用法,見Python語法原理。
def _get_improvement():
# 隨機初始化初代種群,對於遺傳算法來說,初始情況完全不重要
parent = bestParent = fnCustomCreate()
yield bestParent
# 歷史健壯性集合,這個集合可以記錄歷史上一些最佳的健壯性
historicalFitnesses = [bestParent.Fitness]
while True:
child = mutate(parent)
if parent.Fitness > child.Fitness:
# 本節算法用maxAge這個參數來控制單次迭代的數量
# 主要為了解決局部過大或者過小的問題,也就是說
if maxAge is None:
continue
parent.Age += 1
# 初始化的時候設置maxAge為50,表示跟蹤這個父本基因進化50次
# 生成出來的子代基因的健壯性還不如父本的話,這父本基因就直接被設置死亡
# 如果超過了代數,設置這個基因死亡,然後考慮換一個基因來進行替代。
# 劃重點:這是模擬退火算法裡面的核心思維
if maxAge > parent.Age:
continue
# 我們來計算,本次進化的健壯性,在整個歷史進化過程中所有健壯性的位置。
index = bisect_left(historicalFitnesses, child.Fitness, 0,
len(historicalFitnesses))
# 直接把這個位置轉換成比例
proportionSimilar = index / len(historicalFitnesses)
# 如果子代的健壯性很好,那麼它的指數就會很高(如果排名歷史第一(值為0)
# 則指數就會很高,百分之百會讓這個子代變成下一次進化的父本。
# 反之,排名月底,成為父本的概率也就越低
# 就繼續用這個父本進行進化
if random.random() < exp(-proportionSimilar):
parent = child
continue
# 否則,用初始化的父本來替換成需要進化的父本
# 也就是丟棄本輪進化,從新回退到上一次最佳父本的狀態
bestParent.Age = 0
parent = bestParent
continue
# 如果子體的健壯性要比父本好,則子體替換父本,成為新的進化的父本
# 替換了之後,子體的年齡要繼承父本的年齡,並且繼續增長。
if not child.Fitness > parent.Fitness:
child.Age = parent.Age + 1
parent = child
continue
child.Age = 0
parent = child
# 如果本次進化的子體比最佳父本效果還好,那麼用這次進化的子體去替換最好的父本
# 然後把上一次最好的父本加入到歷史父本中。
if child.Fitness > bestParent.Fitness:
bestParent = child
yield bestParent
historicalFitnesses.append(bestParent.Fitness)

def get_best():
startTime = datetime.datetime.now()
optimalFitness = Fitness(0)
# 迭代執行
# 直到到達進化目標
for improvement in _get_improvement():
display(improvement,startTime)
if not optimalFitness > improvement.Fitness:
return improvement

模擬退火算法

退火是一種用於降低金屬等材料內應力的方法。它的工作原理是通過加熱,將金屬升溫到高溫,然後讓它慢慢冷卻。我們都知道,熱量會使金屬膨脹。所以當金屬膨脹的時候,金屬材料之間的粘結會被鬆開,金屬的分子結構就可以進行移動。這時,停止加熱的時候,金屬會緩慢冷卻。當金屬冷卻後,金屬的鍵再次收緊,雜質會被擠壓出來,而且,直到他們相互之間會緊緊的粘合在一起,使之沒有迴旋的餘地,從而減少了系統中的整體應力。

模擬退火是用遺傳算法來突破局部最小或最大的過程。如果子代基因序列離目前的最佳解決方案很遠,那麼我們給它一個很高的概率繼續進化下去。否則,那我們就做別的事情

執行結果如下:

# 最後一行是列的和,左邊和右邊是對角線的和
# 最後那個23,是健壯性
[1, 4, 8] = 13
[3, 9, 6] = 18
[7, 2, 5] = 14
24 [11, 15, 19] 15
- - - - - - - - - - - 23 0:00:00
#……中間結果略
[2, 9, 4] = 15
[7, 5, 3] = 15
[6, 1, 8] = 15
15 [15, 15, 15] 15
- - - - - - - - - - - 0 0:00:05.995768
# 0表示符合預期進化目標,完成進化

下面我們來修改一下我們的方塊,比如改成4*4,修改基本參數如下:

diagonalSize = 4

執行結果如下:

      [5, 13, 3, 2] = 23
[7, 9, 14, 15] = 45
[6, 10, 4, 12] = 32
[16, 8, 11, 1] = 36
42 [34, 40, 32, 30] 19
- - - - - - - - - - - 61 0:00:00
# ……中間結果略

[13, 4, 5, 12] = 34
[16, 7, 10, 1] = 34
[2, 9, 8, 15] = 34
[3, 14, 11, 6] = 34
34 [34, 34, 34, 34] 34
- - - - - - - - - - - 0 0:00:00.233368

最後來一個10*10的,修改基本參數如下:設置maxAge為5000

diagonalSize = 10
maxAge = 5000

這裡運行效率的時候看人品,從幾分鐘到十幾分鐘不等(我這裡這次用了2分多鐘),大家可以自行運行測試,運行結果如下:

      [4, 64, 10, 93, 19, 81, 60, 47, 59, 90] = 527
[16, 15, 24, 14, 21, 71, 48, 50, 40, 2] = 301
[70, 49, 34, 25, 23, 32, 57, 42, 37, 51] = 420
[63, 66, 27, 45, 13, 46, 54, 98, 82, 85] = 579
[7, 99, 6, 97, 87, 75, 33, 17, 20, 96] = 537
[86, 95, 61, 18, 77, 35, 56, 92, 94, 11] = 625
[26, 12, 79, 22, 1, 65, 36, 5, 29, 76] = 351
[67, 53, 100, 83, 39, 73, 62, 38, 89, 55] = 659
[41, 44, 91, 68, 84, 58, 3, 78, 72, 88] = 627
[52, 28, 9, 80, 30, 69, 31, 43, 74, 8] = 424
596 [432, 525, 441, 545, 394, 605, 440, 510, 596, 562] 374
- - - - - - - - - - - 1896 0:00:00

# 中間結果略……
# 最後結果如下:行列對角線,全部等於505

[96, 50, 25, 17, 28, 72, 61, 5, 75, 76] = 505
[66, 93, 18, 39, 83, 31, 78, 49, 8, 40] = 505
[34, 89, 52, 63, 62, 23, 64, 26, 24, 68] = 505
[16, 14, 27, 43, 60, 45, 32, 99, 74, 95] = 505
[47, 20, 56, 87, 88, 73, 19, 69, 42, 4] = 505
[86, 79, 12, 3, 77, 36, 54, 90, 58, 10] = 505
[22, 94, 97, 11, 1, 57, 46, 59, 48, 70] = 505
[55, 2, 98, 85, 44, 71, 33, 15, 67, 35] = 505
[30, 51, 82, 65, 21, 6, 37, 84, 29, 100] = 505
[53, 13, 38, 92, 41, 91, 81, 9, 80, 7] = 505
505 [505, 505, 505, 505, 505, 505, 505, 505, 505, 505] 505
- - - - - - - - - - - 0 0:02:22.627786

有興趣的同學,還可以嘗試修改各種參數,比如maxAge,以及方格數量。


相關焦點

  • 算法基礎:五大排序算法Python實戰教程
    | George Seif翻譯 | 鄧普斯傑弗校對 | shunshun 整理 | 菠蘿妹原文連結:https://medium.com/@george.seif94/a-tour-of-the-top-5-sorting-algorithms-with-python-code
  • 用python實現遺傳算法
    最近事情比較多,一個月沒有寫公眾號了,但也積累了些不錯的內容可以分享,今天就給大家介紹的是遺傳算法,並用python加以實現。在遺傳算法的學習過程中,在CSDN上看到一篇已有人分享的python代碼,因此直接借鑑過來,並結合《數學建模與數學實驗》進行補充。
  • 魔術方塊電腦
    (原標題:魔術方塊電腦) 三星近日發布了全新的個人電腦產品
  • 一文讀懂遺傳算法工作原理(附Python實現)
    其中重點介紹了遺傳算法的數據科學應用。目錄1、遺傳算法理論的由來2、生物學的啟發3、遺傳算法定義4、遺傳算法具體步驟初始化適應度函數選擇交叉變異5、遺傳算法的應用遺傳算法實際上就是這樣工作的,也就是說,它基本上盡力地在某種程度上模擬進化的過程。因此,為了形式化定義一個遺傳算法,我們可以將它看作一個優化方法,它可以嘗試找出某些輸入,憑藉這些輸入我們便可以得到最佳的輸出值或者是結果。遺傳算法的工作方式也源自於生物學,具體流程見下圖:那麼現在我們來逐步理解一下整個流程。
  • Python機器學習實戰 —— KNN算法詳解
    這個系列按照機器學習實戰的章節來寫,由於市面上已經有很多同類的文章,一般以介紹算法,貼代碼,舉例子為主,個人讀下來,覺得對於實現的代碼還是不能有很好的理解,所有有了這個系列。要寫這個系列還有三個原因:實戰的代碼是Python2的,有一些用法已經在python3中不支持了,以後的系列都以pyhton3完成,遇到python2不支持的坑,會進行一下對比有一些初級的函數在初學階段是需要積累的,孤立的去記憶比較費時費力,所以一邊學算法的實現,一邊把遇到的一些函數的用法記錄下來~遇到有趣的pythonic的表達,記錄分享出來,做知識積累。
  • Openai研究用僅單個機器手掌就能解決的魔術方塊
    60%的成功率解開魔術方塊。Openai利用了神經網路來解決魔術方塊的問題,透過增強學習進行模擬,並且使用柯西姆巴(Kociemba)演算法以挑選魔術方塊解法的步驟,並且利用域隨機化(DomainRandomization)將訓練模擬轉移到真實的機器手掌上。
  • 那些有趣/用的 Python 庫,15篇 Python 技術熱文
    其中有基礎知識,工具介紹,網絡爬蟲,遺傳算法等。註:以下文章,點擊標題即可閱讀《那些有趣/用的 Python 庫》本文整理了一些有趣有用的 Python 庫,其中包括圖片處理,視頻下載,財經數據接口包等等,需要的童鞋可以看過來啦。
  • 算法工程師面試問題及資料超詳細合集(多家公司算法崗面經/代碼實戰/網課/競賽等)
    |2019秋招算法崗復盤 website專科生阿里大數據一面面經(已過) website2019秋招算法崗復盤 website我面試了10家算法公司,這是我能記住的所有問題 website計算機視覺算法工程師(曠視、商湯、智雲、海康)面試總結 website秋招面經 | 滴滴20校招CV算法崗面試經驗分享(三面) website
  • Cubestormer 3 創出還原魔術方塊的世界紀錄
    在現正進行的英國 Big Bang Fair 上,兩位 ARM 的工程師 David Gilday 和 Mike Dobson 示範了他們 Cubestormer 3 如再打破還原魔術方塊的世界紀錄。
  • 「python opencv計算機視覺零基礎到實戰」九模糊
    一、學習目標了解什麼是卷積了解模糊的使用方法與應用目錄「python opencv 計算機視覺零基礎實戰」 第一節「python opencv視覺入門到實戰」二、格式與攝像頭「python opencv 視覺入門到實戰」 三、圖像編輯「python opencv視覺入門到實戰」 第四節色彩空間
  • 教程| 基於遺傳算法的拼圖遊戲解決方案
    選自GitHub機器之心編譯參與:林川、劉曉坤這是一個GitHub項目,介紹了一種基於遺傳算法的帶有板塊尺寸自動檢測功能的拼圖遊戲解決方案。連結:https://github.com/nemanja-m/gaps安裝把 repo 下載到本地$ git clone https://github.com/nemanja-m/gaps.git$cdgaps安裝要求$ pip install -r requirements.txt$ sudo apt-get install python-tk
  • [Python] geatpy 多目標遺傳算法求解最短路
    進化算法geatpy調包俠養成文章最後開了個坑,說有空的時候要補上遺傳算法在路徑求解問題中的應用,這次就給大家整一個。問題描述簡單來說,本次的例子是一個多目標無向圖求最短路徑的問題(該問題的原型來自於我同門的論文,危貨的路徑優化)。
  • 第113天: Python XGBoost 算法項目實戰
    XGBoost算法現在已經成為很多數據工程師的重要武器。XGBoost 算法說到XGBoost,不得不提GBDT(Gradient Boosting Decision Tree)。XGBoost高效地實現了GBDT算法並進行了算法和工程上的許多改進,被廣泛應用在Kaggle競賽及其他許多機器學習競賽中並取得了不錯的成績。這一篇最適合剛剛接觸XGBoost的人閱讀,通過一個實戰項目拆解整個XGBoost算法。
  • 今天帶大家用Python代碼,遺傳算法訓一波龍~
    開發工具  Python版本:3.6.4  相關模塊:  numpy模塊;  argparse模塊;  pygame模塊;  以及一些python  原理簡介  遺傳算法,即:  Genetic Algorithm, GA是一種元啟發式算法,其核心思想與達爾文的進化理論很相似。簡單而言就是物種在進化過程中,好的基因將得到保留,不好的基因將被淘汰。經過很多代的演變之後,物種當前保留下來的基因就可以看作是對當前環境適應度最好的基因了。
  • 什麼是遺傳算法?怎樣繪製遺傳算法流程圖
    遺傳算法是一種通過模擬自然進化過程搜索最優解的操作方法,遺傳算法有三個基本算子選擇、交叉和變異。對於遺傳算法我們也可以使用流程圖對其整個過程進行總結歸納,那要怎樣繪製遺傳算法流程圖呢?下面是分享的簡單操作方法,希望可以幫助大家。
  • 三宅一生BAOBAO的魔術方塊穿搭術【圖】
    三宅一生BAOBAO的魔術方塊穿搭術【圖】 2014-10-21 16:17:24 來源:騰訊時尚     一個單品的火紅程度,其實去國貿、新天氣一轉便知
  • golang 調用 python 實戰路徑規劃之 A* 算法
    算法介紹A*(念做:A Star)算法是一種很常用的路徑查找和圖形遍歷算法。它有較好的性能和準確度。本文在講解算法的同時也會提供Python語言的代碼實現,並會藉助matplotlib庫動態的展示算法的運算過程。
  • python機器學習預測分析核心算法.pdf
    《美團機器學習實踐》_美團算法團隊.pdf《深度學習入門:基於Python的理論與實現》高清中文PDF+源碼特徵提取與圖像處理(第二版).pdfpython就業班學習視頻,從入門到實戰項目2019最新《PyTorch
  • Python最佳經典學習路線
    如何學習Python python語言基礎:(帶你熟悉python語言的特性,學會使用python開發環境,使用python開發一些簡單的案例) (1)Python3入門,數據類型,字符串 (2)判斷/循環語句,函數,
  • Python視頻教程網課編程零基礎入門數據分析網絡爬蟲全套Python...
    25python網絡爬蟲 26機器學習入門篇 27機器學習入門篇2 28機器學習提升篇 29數據挖掘篇 30深度學習必備原理與實戰 31深度學習必備原理與實戰2 32深度學習必備原理與實戰3 33深度學習必備原理與實戰4 34深度學習項目實戰 35