遺伝アルゴリズムを用いて関数極値を解く(fortran)

36021 ワード

遺伝アルゴリズムを用いて関数極値を解く(fortran)
  • は前の
  • に書いてあります
  • 遺伝アルゴリズムの前世今生
  • アルゴリズムステップ概要
  • 遺伝アルゴリズムの本体構造
  • 求解:
  • 結果:
  • 最後に注意すべき点
  • についてお話しします
    前に書く
    この文章はいくつかの応急学習最適化アルゴリズムの友达に適しています.大物レベルの学生には直接スキップしてください.結局、編集者もコンピュータとあまり関係のない伝統的な工科生にすぎません.完全なコードはすでに本人のブログの資源にアップロードして、ダウンロードを歓迎します
    編集者が初めて遺伝アルゴリズムに出会ったのは、大学3年生の米試合で、最適化アルゴリズムを学ぶ必要があった.しかし、最適化アルゴリズムとしての遠古レベルの遺伝アルゴリズムは自然に私の最初の学習の目標としている.
    ここで私のGAに対する感じを書いて、このアルゴリズムは知能アルゴリズムに属して、理論的にはグローバル最適化を実現することができますが、しばらくの間の学習を経て、いくつかの複雑な関数に対してグローバル最適化を実現するには本当に運が必要だと感じています.このアルゴリズムは最も古典的で、後期には多くの類似のアルゴリズムが次々と現れ、粒子群アルゴリズム、蟻群アルゴリズムなどがある.ここでは評価をしないで、編集者はその中の1つを勉強すればいいと思っています.
    最后に!!!今回はGAアルゴリズムでいくつかの複雑な関数を完全に計算した.ここでは、後期に戻って復習しないように、いくつかの重要なステップといくつかの心得を示します.(psフルコードは後期に空で送信されます)
    遺伝アルゴリズムの前世今生
    遺伝アルゴリズムの概念は1967年にBagley J.Dによって最初に提案された.その後Michigan大学のJ.H.Holland教授は1975年に遺伝アルゴリズム(Genetic Algorithm,GA)のメカニズムを系統的に研究し始めた.遺伝アルゴリズムはダーウィン生物進化理論の簡単なシミュレーションであり、「適者生存」、「優勝略汰」の原理に従う.遺伝アルゴリズムは1人の職種群の進化過程をシミュレートし,選択,ハイブリダイゼーションおよび変異などの機構により,種群は数世代後,常に最適(または近最適)の状態に達する.
    遺伝アルゴリズムが提案されて以来、それは広範な応用を得ており、特に関数最適化、生産スケジューリング、モード識別、ニューラルネットワーク、適応制御などの分野で、遺伝アルゴリズムはさらに重大な役割を果たし、問題解の効率を大幅に向上させた.遺伝アルゴリズムも現在の「ソフトコンピューティング」分野の重要な研究課題である.
    本文はまずfortranと結びつけて遺伝アルゴリズムの実現過程を詳細に分析し,次に1つの実際の関数最適化事例を通じてその応用を検討した.
    アルゴリズムステップの概要
    多くの人が遺伝アルゴリズムのいくつかの基本的な手順を書いたことがありますが、私はここで贅沢をしないで、直接住所を置いて、みんなは細かいものに行くことができます.このアルゴリズムはもともとこんなに不思議だった.
    https://blog.csdn.net/qq_34374664/article/details/78874956
    前に私の啓発のとても大きいブログに対して探し出せなくて、しかし彼の文章を見終わって私はあなたがGAの大まかな過程に対して1つの理解があることができることを信じます
    見終わったら、私の次の演技を見てください.
    はははははははははははははははははははははははははははははははははははははははははははははははははははははははははははははははははははははははははは
    遺伝アルゴリズムの主体構造
    遺伝アルゴリズムのプログラミングの一環を始めましょう.まず、計算過程全体でどの関数(サブプログラム)を使う必要があるかを考えなければなりません.クラスタ初期化2.クラスタ適応度3を計算する.クラスタ適応度ソート4.操作5を選択(フィルタ)する.クロス操作6.変異操作は以上が必要な関数である.次に、大規模なプログラムを作る意識が必要です.一部のデータはグローバル変数に設定され、常に保存されるため、頻繁に使用される量を事前に整理する必要があります.pop_size:クラスタサイズchromoを入力size:染色体長generation_を入力size:反復回数cross_を入力rate:交差確率cross_を入力rate:変異確率elitismを入力:エリート選択かどうかを入力する(これらの変数は後で使用するときに説明する)
    解法の開始:
    1.クラスタ初期化:
    integer i,j,k
    integer pop_size, chromo_size,pop_num
    real x
    call RANDOM_SEED()
    do i=1,pop_size
        do j=1,pop_num
        do k=1,chromo_size
            call RANDOM_NUMBER(x)
            pop(i,j,k) = nint(x)
        end do
        end do
    end do
    

    言語解釈:pop-sizeの大きさのクラスタの各個体に対して、個体のpop-numの次元に対して、各次元のchromo_sizeサイズの染色体長をランダムに付与した.RANDOM_SEED()__基本的な乱数の発生関数
    2.クラスタ個体の適応度を計算する(異なる最適化目標に対して、ここで書き換える必要がある)
     integer i,j,k
        integer pop_size,pop_num,chromo_size
        real fitness_value1(pop_size,pop_num).
        
    !do  i=1,pop_size(    ,            )
    !   fitness_value(i) = 0.  
    !end do
    
    do i=1,pop_size
       do j=1,pop_num
           do k=1,chromo_size
          if (pop(i,j,k) == 1)then
                fitness_value1(i,j) = fitness_value1(i,j)+2**(k-1)
          end if
          
       end  do     
       fitness_value1(i,j) = -500+fitness_value1(i,j)*(500-(-500))/(2**chromo_size-1)
         
         fitness_value1(i,j) = fitness_value1(i,j)*sin(sqrt(fitness_value1(i,j)))      !*****   *********    
         
         fitness_value(i)=fitness_value1(i,j)+fitness_value(i)
    end do
    
    end do
    

    3.クラスタソート個体を適応度の大きさでソートし、最適個体を保存する
    integer pop_size,pop_num,chromo_size
    integer i,j,k,m,min,temp
    integer temp1(pop_num,chromo_size)
    
    do  i=1,pop_size    
        fitness_table(i) = 0.
    end do
    
    min = 1
    temp = 1
    temp1(pop_num,chromo_size)=0
     do  i=1,pop_size
        min = i
       do j = i+1,pop_size
    if (fitness_value(j)<fitness_value(min))then
                min = j
    end if
    end do
    if (min/=i)then
            temp = fitness_value(i)
            fitness_value(i) = fitness_value(min)
            fitness_value(min) = temp
    do m=1,pop_num
       do k = 1,chromo_size
                temp1(m,k) = pop(i,m,k)
                pop(i,m,k) = pop(min,m,k)
                pop(min,m,k) = temp1(m,k)
       end do
    end do
    
    end if
    
    end do
    
    do i=1,pop_size
    if (i==1)then
            fitness_table(i) = fitness_table(i) + fitness_value(i)   
    else
            fitness_table(i) = fitness_table(i-1) + fitness_value(i)
    end if
    end do
    !fitness_table!***********************????????????????
    fitness_avg(G) = fitness_table(pop_size)/pop_size
    
    
    if (fitness_value(pop_size) > best_fitness)then
        best_fitness = fitness_value(pop_size)
        best_generation = G
    end if
    do i=1,pop_num
    do  j=1,chromo_size
            best_individual(i,j) = pop(pop_size,i,j)
    end do
    end do
    

    4.ルーレット選択操作は「関数山」に分布する異なる種群に対して劣勢な種群を処理する必要がある.処理のルールは,第3ステップで計算した関数適応度の大きさを,各クラスタのホイールディスク上の分布角度の大きさとして利用することである.そして車輪を回して、誰を選んだら、誰が生き残ることができます.その中から明らかなことは、低適応度の最小クラスタに対して最も選択されないことである.運が悪く、優秀な種群が排除されれば、私たちはこれらの優秀な種群に対して「保送」の方式をとることができる.(ここで注意するのは、このような保送の方式を適切に止める必要があり、局所的に最も優れていることを防止することである)
    integer pop_size, chromo_size,elitism,pop_num
    integer i,j,k,p,r,mid,first,last,idx
    real x,w,q
    
    call RANDOM_SEED()
    call RANDOM_NUMBER(x)
    do i=1,pop_size
        r = x * fitness_table(pop_size)
        first = 1
        last = pop_size
        w=(last+first)/2
        mid = nint(w)
        idx = -1
    do while ((first <= last).and.(idx == -1) )
      if (r > fitness_table(mid))then
                first = mid
    else if (r < fitness_table(mid))then
                last = mid  
    else
                idx = mid
    exit
    end if
    q=(last+first)/2
            mid = nint(q)
       if ((last - first) == 1)then
                idx = last
       exit
      end if
    end do
    do k=1,pop_num
        do j=1,chromo_size
            pop_new(i,k,j)=pop(idx,k,j)
        end do
    end do
    end do
    
    !**************************    *************************
    if (elitism==1)then
        p = pop_size-1
    else
        p = pop_size
    end if
    do  i=1,p
        do k=1,pop_num
        do  j=1,chromo_size
            pop(i,k,j) = pop_new(i,k,j)
        end do
    end do
    end do
    

    5.単点交差操作
    implicit none
    integer pop_size, chromo_size,cross_rate,pop_num
    integer i,j,k,cross_pos,temp
    real x
    
    call RANDOM_SEED()
    do i=1,pop_size,2
        do k=1,pop_num
        call RANDOM_NUMBER(x)
        if(x < cross_rate)then
            cross_pos = nint(x * chromo_size)    !    
           if(cross_pos == 0.or.cross_pos == 1)then
             cycle
           end if
           
         do  j=cross_pos,chromo_size
                temp = pop(i,k,j)
                pop(i,k,j) = pop(i+1,k,j)
                pop(i+1,k,j) = temp
         end do
    
    end if
        end do
    end do
    

    6.変異操作
    !pop_size:     
    !chromo_size:      
    !cross_rate:     
    subroutine mutation(pop_size, chromo_size, mutate_rate,pop_num)
    use a10
    implicit none
    integer i,j,mutate_pos
    real x
    integer pop_size, chromo_size,mutate_rate,pop_num
    call RANDOM_SEED()
     do i=1,pop_size
         do j=1,pop_num
        call RANDOM_NUMBER(x)
        if (x < mutate_rate)then
            mutate_pos = nint(x*chromo_size)
            if (mutate_pos == 0)then
            cycle
            end if
            pop(i,j,mutate_pos) = 1 - pop(i,j, mutate_pos)
        end if
        
         end do
     end do
    

    変異操作は交差操作と類似しているが,その影響の大きさには違いがある.交差操作は関数山の種群の間で合コンを行い、それらの間の領土を拡大し、彼らの間の位置の盲区を明らかにすることに相当する.彼は相対的に制御できる.逆変異操作はランダムなジャンプであり,種群はより良い場所に行くか,より悪い場所に行くかのいずれかである.これは,最適な結果を得るために読者自身がパラメータを修正する必要がある.これで、解法が完了しました
    結果:
    ここの元の関数は....適応度計算の変更関数の行、30次元の関数を参照します.次はメイン・プログラムです.
    program GA
    use a10
    implicit none
    !real,external :: fitness***********        
    !integer,external:: rank
    !real,external ::selection
    !real,external :: crossover
    !real,external :: mutation
    
    integer m(30,24),p,j,i
    real n,q(30)
    integer,save::pop_size        !    
    integer ,save::pop_num        !      
    integer,save::chromo_size     !     **********                                      *********  
    integer ,save::elitism        !      
    integer ,save::cross_rate       !    
    integer ,save::mutate_rate     !    
    
    !function [m,n,p,q] = GeneticAlgorithm(pop_size, chromo_size, generation_size, cross_rate, mutate_rate, elitism)
    elitism = 1             !      
    pop_size = 1000           !    
    pop_num=30              !  30
    chromo_size = 24       !     
    generation_size = 200   !    
    cross_rate = 0.5        !    
    mutate_rate = 0.01      !    
    
      
    !print *, '   '
      
      
    fitness_avg = 0.
    
    
    fitness_value(pop_size) = 0.
    best_fitness = 0.
    best_generation = 0
    
    call initilize(pop_size,pop_num,chromo_size)          !   
    
    do  G=1,generation_size   
      call fitness(pop_size,pop_num,chromo_size)                !      
      call  rank(pop_size,pop_num,chromo_size)                  !             
      call selection(pop_size, chromo_size,elitism,pop_num)      !    
      call crossover(pop_size, chromo_size, cross_rate,pop_num)  !    
      call mutation(pop_size, chromo_size, mutate_rate,pop_num)  !    
    end do
    
    
    !****                                               ******************matlab     ****************
    
    
    m = best_individual                   !      
    n = best_fitness                 !       
    p = best_generation                   !         
    
    !         ,        ,      
    q = 0.
    do i=1,pop_num
    do j=1,chromo_size
        if (best_individual(i,j) == 1)then
              q(i)= q(i)+2**(j-1)
        end  if
    end do
    
    
    
    
    !!!!!!!!!!!!!!!!!*********************************           **********************
                                q(i) = -500+q(i)*(500-(-500))/(2**chromo_size-1)
    end do
    
    
    
    
    
    write(*,*)"    "
    write(*,*) m
    write(*,*)"     "
    write(*,*) n
    write(*,*)"       "
    write(*,*) q
    write(*,*)"    "
    write(*,*) p
    
    end program GA
    

    多くの関数を計算したため、最も原始的な1部をタイムリーに保存していないので、中間は少し対応していないかもしれません.しかし、大体の考え方はすでに示されています.
    最後に注意すべき点をお話しします
  • は、バイナリと10進数との間の変換を理解する必要がある.ここでは補間の手法を用いる.
  • は、fortran内の大規模なプログラム作成のモジュール化を理解し、データ呼び出しを容易にする必要がある.

  • 最後に、時間が限られていて、編集者は怠け者で、暇があれば補充します.自分で後で復習しましょう.編集長は水工構造の大学院生で、もしあなたがここまで読んだら、みんなはもっと交流することができます.