遺傳算法求解函數(shù)最大值Java實現(xiàn)

我的《自然計算》作業(yè),搬上來怨咪。

目錄

  1. 概述
  2. 編碼
  3. 初始群體的產(chǎn)生
  4. 適應度計算
  5. 選擇運算
  6. 交叉運算
  7. 變異運算
  8. 測試效果
    參考資料

一,概述

本文在理解遺傳算法的基本原理的基礎上,使用Java語言寫了一個小程序來簡單實現(xiàn)用遺傳算法求解二次函數(shù)f(x,y)=xx+yy (x和y的取值范圍為1到127的正整數(shù))的最大值泳挥。完整源碼見已上傳至我的github,詳情請點擊此鏈接:查看本項目全部代碼

二至朗,編碼

重述一下本文求解的問題:

image.png

由于遺傳算法的運算對象是表示個體的符號串屉符,所以必須把變量x,y編碼為一種符號串。在這里采用無符號二進制整數(shù)來表示锹引。因x,y的取值范圍為1到127,矗钟,則可用兩個7位二進制數(shù)來分別表示它們。而一個基因就是一個14位二進制串嫌变。例如吨艇,基因型00000001111111所對應的表現(xiàn)型是:x=0,y=127。在代碼中的具體體現(xiàn)為:設計類Chromosome腾啥,其具有私有整形字段x,y表示x,y的十進制值秸应、String字段gene表示二進制串。并使用常量定義其最大值或最大長度碑宴。代碼如下:

public static final int GENG_LENGTH = 14;
public static final int MAX_X = 127;
public static final int MAX_Y = 127;
private int x,y;
private String gene;

三软啼,初始群體的產(chǎn)生

遺傳算法是對群體進行的進化操作,所以第一步要產(chǎn)生一個初始種群延柠,再進行后續(xù)的交叉祸挪、變異、選擇等操作贞间。在具體實現(xiàn)上贿条,初始種群的產(chǎn)生較為簡單。首先對類Chromosome進行構(gòu)造函數(shù)的編寫增热,主要寫了以下兩種構(gòu)造函數(shù):
public Chromosome(String gene) //給定基因串構(gòu)造染色體
public Chromosome(int x,int y) //給定表現(xiàn)型構(gòu)造染色體
在這里用到了第二個構(gòu)造函數(shù)整以,首先隨機產(chǎn)生兩個1到127之間的數(shù)作為X,Y,再調(diào)用構(gòu)造函數(shù)生成新染色體并添加到初始種群中去峻仇。如此重復公黑,直到種群規(guī)模達到要求。具體代碼如下:

    public static ArrayList<Chromosome> initGroup(int size) {
        ArrayList<Chromosome> list = new ArrayList<Chromosome>();
        Random random = new Random();
        for(int i = 0; i < size; i++) {
            int x = random.nextInt() % 128;
            int y = random.nextInt() % 128;
            x = x < 0? (-x):x;
            y = y < 0? (-y):y;
            list.add(new Chromosome(x,y));
        }
        return list;
    }

四,適應度計算

遺傳算法中以個體適應度評價其優(yōu)劣程度凡蚜,其最終目的是選擇出適應度較高的個體人断。本文所求解問題,目標函數(shù)總?cè)》秦撝党⑶沂且郧蠛瘮?shù)最大值為優(yōu)化目標恶迈,故可直接利用目標函數(shù)值作為個體的適應度。具體求解代碼如下:

public int calcFitness() {
        return x*x+y*y;
}

五谱醇,選擇運算

選擇運算把當前的群體中適應度較高的個體按照某種規(guī)則或模型遺傳到下一代個體中暇仲。這里我們使用課堂上講的“輪盤賭”的方式進行選擇「笨剩“輪盤賭”的思想這里不再贅述奈附,只說一下JAVA代碼的具體實現(xiàn)過程。
首先計算種群中每個個體的適應度保存到一個數(shù)組里佳晶。在這基礎上計算“累加適應度”桅狠,即第一個適應度為原第一個適應度,第二個為前兩個的和轿秧,第三個為前三個的和中跌,以此類推。再將此數(shù)組每個元素除以總的適應度菇篡。然后進行選擇漩符,選擇次數(shù)和設定好的種群規(guī)模相同(這樣便可以控制種群的規(guī)模不會無限的上漲)。每次選擇時驱还,先產(chǎn)生一個0到1之間的隨機數(shù)嗜暴。在上述數(shù)組中遍歷找到第一個大于此隨機數(shù)的元素,這個元素對應的個體被選擇议蟆。具體代碼如下:

public static ArrayList<Chromosome> selector(ArrayList<Chromosome> fatherGroup,int sonGroupSize) 
{
    ArrayList<Chromosome> sonGroup = new ArrayList<Chromosome>();
    int totalFitness = 0;
    double[] fitness = new double[fatherGroup.size()];
    for(Chromosome chrom : fatherGroup) {
        totalFitness += chrom.calcFitness();
    }
    int index = 0;
    //計算適應度
    for(Chromosome chrom : fatherGroup) {
        fitness[index] = chrom.calcFitness() / ((double)totalFitness);
        index++;
    }
    //計算累加適應度
    for(int i = 1; i < fitness.length; i++) {
        fitness[i] = fitness[i-1]+fitness[i];
    }
    //輪盤賭選擇 
    for(int i = 0; i < sonGroupSize; i++) {
        Random random = new Random();
        double probability = random.nextDouble();
        int choose;
        for(choose = 1; choose < fitness.length - 1; choose++) {
            if(probability < fitness[choose])
                break;
            }
            sonGroup.add(new Chromosome(fatherGroup.get(choose).getGene()));
        }
        return sonGroup;
    }

六闷沥,交叉運算

交叉運算是遺傳算法中產(chǎn)生新個體的主要操作過程,它以某一概率相互交換某兩個個體之間的部分染色體咐容。本文采用單點交叉的方法舆逃,具體操作過程是:先對群體進行隨機配對;其次隨機設置交叉點位置戳粒;最后再相互交換配對染色體之間的部分基因路狮。
具體的算法流程按照老師課件上講的,這里也不贅述了蔚约。只說一下具體代碼實現(xiàn)原理奄妨。這個算法的要點在于隨機配對個體進行交叉、字符串的拼接操作和生成新個體苹祟。隨機配對可以使用一個do while循環(huán)砸抛,選擇兩個不同的個體评雌。然后隨機選取交叉點,進行兩個基因字符串的交叉锰悼。最后生成新的個體柳骄,采用以下構(gòu)造函數(shù)生成新的個體:public Chromosome(String gene)团赏。
具體代碼如下:

public static ArrayList<Chromosome> corssover(ArrayList<Chromosome> fatherGroup,double probability) {
        ArrayList<Chromosome> sonGroup = new ArrayList<Chromosome>();
        sonGroup.addAll(fatherGroup);
        Random random = new Random();
        for(int k = 0; k < fatherGroup.size() / 2; k++) {
            if(probability > random.nextDouble()) {
                int i = 0,j = 0;
                do {
                    i = random.nextInt(fatherGroup.size());
                    j = random.nextInt(fatherGroup.size());
                } while(i == j);
                int position = random.nextInt(Chromosome.GENG_LENGTH);
                String parent1 = fatherGroup.get(i).getGene();
                String parent2 = fatherGroup.get(j).getGene();
                String son1 = parent1.substring(0, position) +                                          parent2.substring(position);
                String son2 = parent2.substring(0, position) +                                          parent1.substring(position);
                sonGroup.add(new Chromosome(son1));
                sonGroup.add(new Chromosome(son2));
            }
        }
        return sonGroup;
    }

七箕般,變異運算

變異運算是對個體的某一個或某一些基因按某一較小的概率進行改變,它也是產(chǎn)生新個體的一種操作方法舔清。本文中我們采用如下方式進行變異:遍歷群體中所有個體的所有基因位丝里,以一個較小的概率對每個基因位進行變異操作即1變成0,0變成1。在Java代碼中具體實現(xiàn)時体谒,我們先編寫一個函數(shù)對一個個體的基因進行改變杯聚,即用新基因串代替舊基因串。該函數(shù)編寫如下:

public void selfMutation(String newGene) {
        if(newGene.length() != Chromosome.GENG_LENGTH)
            return;
        this.gene = newGene;
        String xStr = newGene.substring(0, Chromosome.GENG_LENGTH/2);
        String yStr = newGene.substring(Chromosome.GENG_LENGTH/2);
        this.x = Integer.parseInt(xStr,2);
        this.y = Integer.parseInt(yStr,2);
}
然后抒痒,按照上述說法對每一位基因進行遍歷幌绍,按指定概率進行變異操作。具體代碼如下所示:
public static void mutation(ArrayList<Chromosome> fatherGroup,double probability) {
        Random random = new Random();
        Chromosome bestOne = Chromosome.best(fatherGroup);
        fatherGroup.add(new Chromosome(bestOne.getGene()));
        for(Chromosome c : fatherGroup) {
            String newGene = c.getGene();
            for(int i = 0; i < newGene.length();i++){
                if(probability > random.nextDouble()) {
                    String newChar = newGene.charAt(i) == '0'?"1":"0";
                    newGene = newGene.substring(0, i) + newChar +                                   newGene.substring(i+1);
                }
            }
            c.selfMutation(newGene);
        }
}

八故响,測試效果

以上實現(xiàn)了所有子模塊傀广。下面使用上述模塊進行實際的遺傳算法求解操作。首先產(chǎn)生初始種群彩届,按照交叉伪冰、變異、選擇的順序進行循環(huán)樟蠕,直到選出符合要求的個體贮聂,這里設置的條件為適應度大于等于32258時終止,這也是本題中能達到的最大適應度寨辩。

final int GROUP_SIZE = 20;//種群規(guī)模
final double CORSSOVER_P = 0.6;//交叉概率
final double MUTATION_P = 0.01;//變異概率
ArrayList<Chromosome> group =                                               Chromosome.initGroup(GROUP_SIZE);
Chromosome theBest;
do{
    group = Chromosome.corssover(group, CORSSOVER_P);
    Chromosome.mutation(group, MUTATION_P);
    group = Chromosome.selector(group, GROUP_SIZE);
    theBest = Chromosome.best(group);
    System.out.println(theBest.calcFitness());
}while(theBest.calcFitness() < 32258);

如上述代碼所示吓懈,在每次迭代后輸出當前種群中的最優(yōu)個體。下面進行了三次測試靡狞。最優(yōu)個體適應度隨種群代數(shù)變化圖耻警,如下圖所示(三次的結(jié)果)∷H粒可以看出隨著迭代次數(shù)的增加榕栏,種群中的最優(yōu)個體適應度總體呈上升趨勢,最終一般在50代之內(nèi)就會找到滿足要求的個體蕾各。

image.png
image.png
image.png

參考資料:

[1]遺傳算法的例子 http://blog.csdn.net/b2b160/article/details/4680853/
[2]老師的課件 cn01-IntroGA-v1.00.ppt


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扒磁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子式曲,更是在濱河造成了極大的恐慌妨托,老刑警劉巖缸榛,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異兰伤,居然都是意外死亡内颗,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門敦腔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來均澳,“玉大人,你說我怎么就攤上這事符衔≌仪埃” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵判族,是天一觀的道長躺盛。 經(jīng)常有香客問我,道長形帮,這世上最難降的妖魔是什么槽惫? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮辩撑,結(jié)果婚禮上界斜,老公的妹妹穿的比我還像新娘。我一直安慰自己槐臀,他們只是感情好锄蹂,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布智政。 她就那樣靜靜地躺著碾盐,像睡著了一般闽寡。 火紅的嫁衣襯著肌膚如雪叨吮。 梳的紋絲不亂的頭發(fā)上咖城,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天蕾额,我揣著相機與錄音崭庸,去河邊找鬼梳玫。 笑死谍珊,一個胖子當著我的面吹牛治宣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播砌滞,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼侮邀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贝润?” 一聲冷哼從身側(cè)響起绊茧,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎打掘,沒想到半個月后华畏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鹏秋,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年亡笑,在試婚紗的時候發(fā)現(xiàn)自己被綠了侣夷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡仑乌,死狀恐怖百拓,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绝骚,我是刑警寧澤耐版,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布祠够,位于F島的核電站压汪,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏古瓤。R本人自食惡果不足惜止剖,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望落君。 院中可真熱鬧穿香,春花似錦、人聲如沸绎速。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纹冤。三九已至洒宝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萌京,已是汗流浹背雁歌。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留知残,地道東北人靠瞎。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像求妹,于是被迫代替她去往敵國和親乏盐。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容