基於遺傳算法的優化問題求解

生物學中的進化論的核心爲「物競天擇,適者生存」,暗含了的規則是生物可否生存是不定的,可是適應環境的生物更容易生存。生物的多樣性可以保持來源於繁殖和變異。
沒錯,你沒有點錯,這的確是一篇有關人工智能入門的博客。開篇先提到一些生物學的觀點是由於,人工智能中遺傳算法的靈感來源於生物學,它是一種仿生的概念。java

一.遺傳算法
那麼,什麼是遺傳算法呢?咱們來舉個栗子吧。
在爬蟲動物園裏有着各類各樣的螞蟻,我想選出一種螞蟻來表明動物園去參加全城動物園的螞蟻戰鬥比賽。那我該怎麼選呢?這裏有一個聰明人提出了一個方法:首先,咱們從各個螞蟻的種羣中選擇出一部分來(選擇初代種羣),讓他們相互打架,而後把勝者留下來互相繁殖(交叉產生子代,選擇了比較好的基因進行遺傳)。把小螞蟻養大,而後再讓它們打架,勝者繁殖(不斷生成子代)。經過屢次的繁殖和選擇,動物園有極大的可能選出的螞蟻是全部螞蟻中打架最厲害的。
好吧,這個例子不是特別的好。我理解的遺傳算法,就是一個多點的不定向搜索。它經過屢次的實驗,來找到符合適應度函數的個體。算法

二.基本步驟
基本的步驟以下:
1.編碼:將咱們能夠用來搜索的部分編碼,經常使用二進制串
2.產生初代:
3.計算每一個個體的適應度及適應度佔整體的比例(這裏我使用了輪盤賭方案):
4.以交叉機率選擇父代母代進行交叉
5.以變異機率進行變異
6.生成知足種羣容量的子代
7.進化多代segmentfault

三.代碼及說明
Java代碼:dom

import java.math.BigDecimal;
import java.util.Random;

public class Genetic {
    int geneSize = 20;
    int populationSize = 50;
    int iterationNum =100;
    double crossoverPro =0.8;
    double mutationPro = 0.05;
    int [][] individual = new int[populationSize][geneSize];
    double [] realValue =new double[populationSize];
    double [] fitness =new double [50];
    double [] fitnessPro =new double [populationSize];
    double currentOpt =0;
    int currentX =0;
    Random random =new Random();
    double [] max =new double[iterationNum];

    public void init(){
        for(int i =0;i<populationSize;i++){    
            for(int j =0;j<geneSize;j++){
                if(random.nextBoolean())
                    individual[i][j] =1;
                else 
                    individual[i][j] =0;
            }
        }
    }
    
    private void CalRealValue(){
        for(int i =0;i<populationSize;i++){
            realValue[i] =0;
            double decimal = 0;
            for(int j =0;j<3;j++){
                realValue[i] = realValue[i]*2+individual[i][j];
            }
            for(int j =geneSize-1;j>=3;j--){
                decimal = decimal/2+individual[i][j];
            }
            realValue[i] += decimal/2; 
        }
    }
    
    private void CalFitnessAndFitnessPro(){
        double sum =0;
        currentOpt =0;
        currentX =0;
        for(int i =0;i<populationSize;i++){    
            fitness[i] = realValue[i]+10*Math.sin(5*realValue[i])+7*Math.cos(4*realValue[i])+17;
            if(currentOpt<fitness[i]){
                currentOpt =fitness[i];
                currentX =i;
            }
            sum+=fitness[i];
            
        }
        double section =0;
        for(int i =0;i<populationSize;i++){
            section +=fitness[i];
            fitnessPro[i] = section/sum;
        }
    }
    
    private void Reproduction(){
        int [][] temp =new int [populationSize][geneSize];
        
        //交叉
        for(int i =0;i<populationSize-1;i=i+2){
            int [] father =new int [geneSize];
            double pro = random.nextDouble();
            for(int j=0;j<populationSize;j++){
                if(fitnessPro[j]>=pro){
                    for(int k =0;k<geneSize;k++)
                        father[k] = individual[j][k];
                    break;
                }
            }
            pro =random.nextDouble();
            int [] mother =new int [geneSize];
            for(int j=0;j<populationSize;j++){
                if(fitnessPro[j]>=pro){
                    for(int k =0;k<geneSize;k++)
                        mother[k] = individual[j][k];
                    break;
                }            
            }
            double pm =random.nextDouble();
            if(pm<crossoverPro){
                int changePosition =random.nextInt(geneSize);
                for(int j=0;j<geneSize;j++){
                    if(j<changePosition){
                        temp[i][j] =father[j];
                        temp[i+1][j] = mother[j];
                    }
                    else {
                        temp[i][j] = mother[j];    
                        temp[i+1][j] = father[j];
                    }
                }
            }else{
                for(int j=0;j<geneSize;j++){
                        temp[i][j] =father[j];
                        temp[i+1][j] = mother[j];
                }
            }
        }
        
        for(int i =0;i<geneSize;i++){
            individual[populationSize-1][i] = individual[currentX][i];
        }
            
        //變異
        for(int i =0;i<populationSize-1;i++){    
            for(int j =0;j<geneSize;j++){
                if(random.nextDouble()<mutationPro)
                    individual[i][j] = 1- temp[i][j];
                else 
                    individual[i][j] = temp[i][j];
            }
        }    
    }
    
    public Genetic(){
        init();
        for(int i =0;i<iterationNum;i++){
            CalRealValue();
            CalFitnessAndFitnessPro();
            BigDecimal optTemp =new BigDecimal(currentOpt-17);
            BigDecimal valueTemp =new BigDecimal(realValue[currentX]);
            optTemp =optTemp.setScale(5, BigDecimal.ROUND_HALF_UP);
            valueTemp =valueTemp.setScale(5, BigDecimal.ROUND_HALF_UP);
            System.out.println("第"+i+"代,最大值爲:"+optTemp+"      對應X是:"+valueTemp);
            max[i] = currentOpt-17;
            Reproduction();
        }
    }

    public double[] getMax(){
        return max;
    }
    
    public static void main(String[] args) {
        
        Genetic genetic =new Genetic();
    }
}

這裏我使用了二進制編碼,單點交叉,輪盤賭加精英選擇(沒代向下完整保留最優個體)。我目標是計算f(x) = x+ 10sin5x + 7cos4x 在[0,9]區間上的極大值,之因此在適應度函數里加入還加了17是由於f(x)在某些位置的時候是取到負數(最小-17),而參與輪盤賭計算的函數必須是正數,因此我加了17.函數

四.小嚐試
二進制編碼在0.001這樣的數的時候是不精確的,因而我想能不能用十進制來解決這個問題呢?下面我嘗試作了十進制編碼(精確度是0.00001)
Java代碼:性能

import java.math.BigDecimal;
import java.util.Random;

public class DecimalGenetic {
    int geneSize = 6;
    int populationSize = 50;
    int iterationNum =100;
    double crossoverPro =0.8;
    double mutationPro = 0.01;
    int [][] individual = new int[populationSize][geneSize];
    double [] realValue =new double[populationSize];
    double [] fitness =new double [50];
    double [] fitnessPro =new double [populationSize];
    double currentOpt =0;
    int currentX =0;
    Random random =new Random();
    double []max =new double[iterationNum];
    
    public void init(){
        for(int i =0;i<populationSize;i++){        
            for(int j =0;j<geneSize;j++){
                if(j == 0)
                    individual[i][j] =random.nextInt(9);
                else
                    individual[i][j] =random.nextInt(10);
            }        
        }
    }
    
    private void CalRealValue(){
        for(int i =0;i<populationSize;i++){
            realValue[i] =0;
            realValue[i]+=individual[i][0];
            double decimal = 0;
            for(int j =geneSize-1;j>0;j--){
                decimal = decimal/10+individual[i][j];
            }
            realValue[i] += decimal/10; 
        //    System.out.println(realValue[i]+"   "+i);
        }
    }
    
    private void CalFitnessAndFitnessPro(){
        double sum =0;
        currentOpt =0;
        currentX =0;
        for(int i =0;i<populationSize;i++){    
            fitness[i] = realValue[i]+10*Math.sin(5*realValue[i])+7*Math.cos(4*realValue[i])+17;
            if(currentOpt<fitness[i]){
                currentOpt =fitness[i];
                currentX =i;
            }
            sum+=fitness[i];    
        }
        double section =0;
        for(int i =0;i<populationSize;i++){
            section +=fitness[i];
            fitnessPro[i] = section/sum;
        }
    }
    
    private void Reproduction(){
        int [][] temp =new int [populationSize][geneSize];
        
        //產生交叉
        for(int i =0;i<populationSize-1;i=i+2){
            int [] father =new int [geneSize];
            double pro = random.nextDouble();
            for(int j=0;j<populationSize;j++){
                if(fitnessPro[j]>=pro){
                    for(int k =0;k<geneSize;k++)
                        father[k] = individual[j][k];
                    break;
                }
            }
            pro =random.nextDouble();
            int [] mother =new int [geneSize];
            for(int j=0;j<populationSize;j++){
                if(fitnessPro[j]>=pro){
                    for(int k =0;k<geneSize;k++)
                        mother[k] = individual[j][k];
                    break;
                }            
            }
            double pm = random.nextDouble();
            if(pm<crossoverPro){
                int changePosition =random.nextInt(geneSize);
                for(int j=0;j<geneSize;j++){
                    if(j<changePosition){
                        temp[i][j] =father[j];
                        temp[i+1][j] =mother[j];
                    }
                    else {
                        temp[i][j] = mother[j];    
                        temp[i+1][j] = father[j];    
                    }
                }
            }
            else{
                for(int j=0;j<geneSize;j++){
                    temp[i][j] =father[j];
                    temp[i+1][j] =mother[j];
                }
            }
        }
        
        for(int i =0;i<geneSize;i++){
            individual[populationSize-1][i] = individual[currentX][i];
        }
            
        //變異
        for(int i =0;i<populationSize-1;i++){
            for(int j =0;j<geneSize;j++){
                if(random.nextDouble()<mutationPro)
                    individual[i][j] = random.nextInt(10);
                else 
                    individual[i][j] = temp[i][j];
            }
        }
    }
    
    public DecimalGenetic(){
        init();
        for(int i =0;i<iterationNum;i++){
            CalRealValue();
            CalFitnessAndFitnessPro();
            BigDecimal optTemp =new BigDecimal(currentOpt-17);
            optTemp =optTemp.setScale(5, BigDecimal.ROUND_HALF_UP);
            System.out.println("第"+i+"代,最大值爲:"+optTemp+"      對應X是:"+realValue[currentX]);
            max[i] = currentOpt-17;
            Reproduction();
        }
    }
    
    public double[] getMax(){
        return max;
    }

    
    public static void main(String[] args) {
        DecimalGenetic decimalGenetic =new DecimalGenetic();
    }

}

實現和二進制大部分一致,可是在變異部分我用了取隨機數這個方法。編碼

五.思考:
關於編碼,我在作完以後有一些思考,想和你們分享.咱們編碼一個數據,用0-1串表示,每一位是沒有差異的,可是轉換爲數字的時候,每一位的權值是不一樣的。對於真正的天然界,每一個性狀對於生物的存活概率的影響也是不一樣的。好比果蠅的翅膀大小和眼色對於它的生存概率的影響是不一樣的,那反應成咱們這裏的編碼就是位置不一樣,權重不一樣.這裏算是遺傳算法的奇妙之處吧.人工智能

下面推薦一個講述比較完整的博客:http://www.javashuo.com/article/p-hcdqmajn-hb.htmlcode

相關文章
相關標籤/搜索