1. 程式人生 > >基於建築專案工程的資金與工期優化問題的遺傳演算法描述

基於建築專案工程的資金與工期優化問題的遺傳演算法描述

目錄

1 問題描述

2 關於遺傳演算法的生物基礎

3 演算法描述

3.1 演算法設計

3.2 遺傳演算法的基本流程

3.3 編碼方式-解的標識

3.4 適應度的評估

3.5 演算法引數設定

3.6 產生初始種群的策略

4 演算法細節

4.1 輪盤賭策略

4.2 選擇運算元

4.3 雜交運算元

4.4 變異運算元

4.5 貸款碼設計

4.6 淘汰策略

5 解函式的設計


1 問題描述

建築企業是面向專案的一類企業,每一個工程專案的建設過程分為若干個施工作業,這些施工作業要滿足一定的前後關係,並且一部分施工作業的開始時間在一定範圍內可以調整。每一項施工作業都要耗費資源,如材料、勞動力、機器工時,資源耗用的過程就是承包商成本發生的過程,也是資金耗用的過程。資源的使用量依據每一項施工活動的內容和開始時間確定。每月末,專案部會從業主那裡收取到工程進度款,形成專案的資金收入,但是同時在月末的時候還需要繳納各種間接費用,如管理費、措施費、規費等。由於建築工程往往耗資巨大,因此工程建設過程中施工企業僅僅依靠自有的資金和業主支付的工程進度款是不夠的,專案部經常需要向公司借款,公司會規定一個貸款的限額(200W),同時專案部也根據貸款金額和利息率想公司支付利息,所以專案部可以在一定範圍內通過調整各個施工作業的開始時間,來達到調整專案資金使用量的目的,使得專案建設過程中的資金使用量不會超過貸款限額,同時貸款利息最少,即專案利潤最大。但是,利息的多少和工期完成是直接關聯的,如果在施工的過程中,貸款少,利息少了,那麼有可能會造成工期延長,那麼也許會使得間接費用管理費、規費、措施費等太大多貸款造成的利息,這樣就不符合優化原則,同時如果貸款過多,也許會造成利息過大,同時也會增大整體專案的開銷。因此,問題就是要尋找一種最優的方法,使得貸款造成的利息和工期生成的間接費用達到平衡從而使得專案開銷最少,利潤最大。

2 關於遺傳演算法的生物基礎

19世紀中葉,查爾斯·達爾文(Charles Darwin)在總結前人進化思想的基礎上,用大量的科學事實證明了生物進化過程總體上表現為:從低階到高階,從簡單到複雜,從不完善到完善,從單一適應到多種適應,從低的有序性到高的有序性,以及沿著物種數目日益增多的方向發展進化。達爾文認為,生物進化的動力和機制在於自然選擇,自然選擇是以變異為基礎,並通過生存競爭實現。凡是具有適應環境的有利變異的個體,在生存競爭中將有更多機會生存和繁殖後代,而較差適應性的個體將被淘汰。因此,生物進化便是物競天擇,適者生存的過程。1975年,美國密歇根大學(University of Michigan

)的心理學教授、電子工程學與電腦科學教授John.H.Holland研究出了具有開創意義的遺傳演算法理論和方法。遺傳演算法是一種借鑑生物界自然選擇和進化機制發展起來的高度並行、隨機、自適應搜尋演算法。它使用了群體搜尋技術,用種群代表一組問題解,通過對當前種群施加選擇、雜交和變異等遺傳操作,從而產生新一代種群,並逐步使種群進化到包含有近似最優解的狀態。由於其處理問題的簡單性,遺傳演算法已經被廣泛使用。近年來,遺傳演算法與問題求解、優化組合、智慧控制等一道成為計算智慧研究中的熱點,受到了廣泛的關注。

3 演算法描述

通過實際專案的問題描述,我們不難知道,演算法主要解決的問題是對整個建築專案造成的資金耗費的一個優化,通過演算法的優化可以給出一套使得整個專案開銷最少,而且同時工期也儘量最短的方案。根據遺傳演算法的性質,這裡主要考慮的是資金問題,因為工期以及進度款等的因素會造成貸款的情況,而貸款又會產生利息,這樣就會造成開銷增大,但是如果不貸款,而是選擇工期的延後,那麼又可能會造成整個工期的增長,從而增大了每月的間接費用以及罰款,而演算法要做的就是給出一個合理的優化,使得貸款金額以及工期延後造成的開銷達到一個平衡。

3.1 演算法設計

根據實際的專案,我們需要解決如下的幾個方面的問題:

選擇編碼方式,並且給出一個包含各個工序號的順序碼,用來確定可以並行開工的工序的先後開工順序。

根據各個工序的不同的先後順序以及工序見開工與完成的限制條件,需要給出一個正確的各個工期的開工排序碼。

設計一種可以儘量使得適應度最優的貸款策略,設計一條貸款碼,為每道工序都設計一個貸款量,並隨著編碼的交叉和變異也進行變化,從而使得貸款碼能夠符合遺傳演算法的要求。

關於演算法的選擇、交叉、變異和淘汰策略的選擇和制定。

適應度函式的設計。

3.2 遺傳演算法的基本流程

遺傳演算法的3個主要操作是:選擇(selection)運算元、交叉(crossover)運算元、變異(mutation)運算元,遺傳演算法中包含了如下的5個基本要素:

對引數進行編碼;

設定初始種群大小;

適應度函式的設計;

遺傳操作設計;

控制引數設定(包括種群大小、最大進化代數、交叉率、變異率等)

3.3 編碼方式-解的標識

任何單個的n個工序的排列表示一個解(對n個工序的數序完工),近似最優解是利潤最大,資金耗費最少的那個。若採用二進位制編碼表示,對次問題的解決沒有任何的優點。相反,若採用二進位制程式碼表示,還要求有特殊的修補演算法,因為單個位的變化可能引起一個非法的工序。於是,本演算法中對解(群體中的個體)的表示統一採用整數編碼的方法。如:“1—3—2—5—4—9—7—8—6”表示一個染色體(個體或路徑),每一個整數代表一個頂點(工序)的編號。

3.4 適應度的評估

此類問題的適應度函式從直觀上來說還是比較容易的,但是排程問題存在許多種情況和各種其他的外部條件約束,因此在實現的時候是比較困難的。但是對於任何可能的解,我們是都可以計算出其最後消耗的資金量和剩餘的資金量,而這裡就將整個工序的總得資金耗費取作它的適應函式值。在專案群體中,我們可以非常容易地比較其中任何兩個染色體的適應函式值,而同樣在本演算法中對適應函式的評估是通過計算群體中單個染色體在整個工程完結過程中所發生資金耗費包括直接工程費、間接工程費、貸款利息、罰金等之和作為適應函式值來實現的。

3.5 演算法引數設定

maxruns:演算法執行次數   lchrom:染色體長度   maxgen:最大時世代數

popsize:種群大小        pcross:交叉概率     pmutation:變異概率

3.6 產生初始種群的策略

設定一個臨時陣列tmp[],用於儲存待處理的lchrom個工序的工序號。在tmp[]陣列的lchrom個工序號中選擇其中一個,記下該工序在臨時陣列中的位置a,且將這一工序作為初始群體中第一個個體的順序碼中的第一個工序,然後將tmp[]陣列中位置為a和lchrom的兩個元素交換;再在tmp[]陣列的前lchrom-1個工序中隨機選擇一個工序,記下該工序在臨時陣列中的位置a,且將這一工序作為初始群體中第一個個體的順序碼中的第二個個體,然後將tmp[]陣列中位置為a和lchrom-1的兩個元素交換。依此類推,迴圈lchrom次,即產生了初始群體的第一個個體的順序碼。用以上同樣的方法迴圈POPSIZE次,即可生成初始群體。

4 演算法細節

4.1 輪盤賭策略

賭輪盤選擇個體方法類似於搏彩遊戲中的賭輪盤。群體中的每個個體的適應度值按比例轉化為選中概率,將輪盤分成POPSIZE個扇區。產生一個[0,1]之間的隨機數m,然後從第一個個體的選中概率開始累加,直到累加概率之和t大於或等於m,將最後被累加選中概率的個體挑選出來。這一操作相當於轉動一次輪盤,被選中的個體相當於輪盤停止轉動時,指標所指向的輪盤扇區。不過,在處理本例項問題時,由於最優解為群體中適應度值最小的個體,因此,在採用賭輪盤策略時應將群體中的各個個體的適應度值按反比例轉化為選中的概率。

4.2 選擇運算元

選擇運算元其實就是賭輪盤策略,但是在本例項中,從原始種群中選擇新種群的時候,採用的是4選2的選擇策略。

在進行交叉和變異之前,需要從oldpop種群中通過賭輪盤策略選擇兩個個體,然後進行交叉和變異操作會生成兩個新個體,那麼在像newpop種群中插入新的個體的時候,根據遺傳演算法的基本原理,我們採用了4選2的策略,從新舊四個個體中選擇出兩個最優的個體。從而來保證生成的新的種群中不會因為交叉和變異的因素導致優秀的解丟失。

4.3 雜交運算元

雜交策略採用的是順序(OX)雜交策略。

演算法的基本思想是:通過賭輪盤策略,從父代中選擇兩個個體,利用順序雜交(OX)策略,通過從一個親體中挑選一個個體的工序序列的子序列並儲存另一個親體的個體的工序序列的相對次序來構造兩個新的個體,生成兩個新個體,然後採用選擇運算元將得到的兩個個體新增到子代中去。下面詳細介紹一下本例項中採用的順序雜交策略。

假如,有Parent1、Parent2兩個父個體(切割點以“|”來區分):

Parent1: 1 2 3 |4 5 6 7| 8 9   Parent2: 4 5 2| 1 8 7 6| 9 3

通過雜交之後,得到子代個體為:

Child1: 2 1 8 |4 5 6 7| 9 3     Child2: 3 4 5 |1 8 7 6 |9 2 

在本例中,可以看到,染色體長度lchrom為9,那麼從父代進行雜交生成子代要經歷一下幾個步驟:

先隨機選擇p1、p2點,p1=rand()%( lchrom+1) ;p2=rand()%( lchrom+1) ,然後進行判斷,最後使得p2-p1>=1,這時候就取得p1和p2了,這裡根據生成的子代我們是假設取得p1=3,p2=7的。

取出Parent1中4 5 6 7和P2中的1 8 7 6 分別放到Child1、Child2中對應的位置中 (藉助p1、p2) 。

生成Child1,將Parent2中的資料從9開始依次從後轉到前面開始存到一個數組tmp [lchrom] 中順序為:9 3 4 5 2 1 8 7 6。

然後向Child1中插入資料,從tmp中依次取出資料,拿每次取出的資料同Child1中已經存在那幾個資料一一對比(這裡隨著向Child1中不斷插入資料,所以,Child1中的資料個數也在變化),如果和Child1中已經存在的相同的資料,那麼捨去;如果沒有存在與之相同的資料,那麼將這個資料順序插入到Child1中去,這樣重複操作,直到tmp陣列中資料輪詢完畢。同樣可以生成Child2。

4.4 變異運算元

變異運算元的設計相對來說不如交叉運算元複雜,其基本思想是:隨機從父代中選擇兩個個體,然後隨機選取個體中的兩個元素,再交換它們的位置。然後將經變異後的兩個個體插入到子代中。

假如,有Parent1、Parent2兩個父個體(切割點以“|”來區分):

Parent1: 1 2 |3| 4 5 6 7 |8| 9   Parent2: 4 5 |2| 1 8 7 6 |9| 3

通過變異運算元,得到的子代如下:

Child1: 1 2 |8| 4 5 6 7 |3| 9   Child 2: 4 5 |9| 1 8 7 6 |2| 3

變異操作最開始其實和交叉類似,都是需要先從父代種群中隨機的取出兩個子代,然後,通過隨機函式,選取兩個點p1,p2,這裡,p1不等於p2,而且p1和p2都是小於染色體長度的,取得亮點之後,在父代中找到它們對應的位置,並交換對應位置上的數字,這樣就完成了變異。

4.5 貸款碼設計

貸款碼的設計,類似工序的編碼設計,也選擇順序編碼,為每一道工序都設計一個貸款碼,在發生貸款的時候,根據當前工序對應的貸款碼進行計算然後得出貸款金額即可。在本專案中,設計的貸款碼長度為10,沒道工序對應的貸款碼都是從0-10之間的隨機數。在生成初始種群的時候,同樣也會為每一道工序都附上他們的隨機的貸款碼。

在父個體交叉生成子個體的時候,貸款碼也是會隨著變化,之前關於交叉的時候可以知道,在染色體中,有些個體的位置不發生變化,那麼它們對應的貸款碼也不發生變化,主要變化的部分就是發生變化的部分,發生變化的部分的貸款碼,等於它在父個體1中原來的貸款碼加上它在新個體中的位置對應的父個體中的貸款碼之和除以2。這裡可能會存在有小數的情況,那麼在程式中採取了變相的四捨五入的操作,即,如果得到的數字下於1的話就讓等於1,其他的按照四捨五入的做法來取。

變異的時候,相對來說就比較簡單,這裡面採取直接進行交換個體的貸款碼也隨著個體移動而移動。

4.6 淘汰策略

淘汰思想:由兩個父代個體生成兩個子代個體,但是在選擇新種群的個體的時候是從新舊四個個體中選擇最優的兩個個體放入到新的種群中去的,這樣使得最優策略始終都能存在。

5 解函式的設計

關於解函式,其實就是適應度函式的設計。在本專案中,關於適應度函式的設計有一條主線,那就是將給定的無序的工序的順序碼按照各個工序間的先後約束關係以及各個工序間的前後完成開工約束來給出一條符合實際要求的正確的排序碼,同時在生成這條排序碼的過程中,來計算整個工程的開銷、各個工序間的開工時間、結束時間、延後時間、前提時間、貸款金額、利息等等。而根據實際的工程問題,在適應度函式中,需要先獨自處理第一道工序,並且還需要獨自處理最後一道工序,然後中間的工序交給核心邏輯函式來處理。