2009-11-27 120 views
2

我正在做一些遺傳算法的工作,並且想寫我自己的GA類。由於遺傳算法可以有不同的方式進行選擇,變異,交叉,生成初始種羣,計算適應度以及終止算法,所以我需要一種方法來插入這些方法的不同組合。我最初的方法是創建一個抽象類,將所有這些方法定義爲純虛擬,任何具體的類都必須實現它們。例如,如果我想嘗試兩個相同但具有不同交叉方法的GAs,則必須創建一個從GeneticAlgorithm繼承的抽象類,並實現除交叉方法之外的所有方法,然後創建兩個具體類它從這個類繼承,只實現了交叉方法。這樣做的缺點是每次我想換出一兩個方法來嘗試新的東西時,我必須創建一個或多個新類。如何構造遺傳算法類層次結構?

是否有另一種方法可以更好地應用於此問題?

回答

1

我會將遺傳算法看作是許多對象的協作,而不是一個封裝整個算法的大類。基本上,您可以爲每個大型變體提供一個抽象類,併爲每個實現選擇提供具體類。然後,您將您想要的具體課程合併爲多種GA。

此外,您可能需要熟悉與策略模式: http://en.wikipedia.org/wiki/Strategy_pattern

1

我認爲你是在你的方式複雜化的東西。建議您下載GAlib包。即使您只以html或pdf格式拉取文檔。這些庫已經存在了一段時間,我真的相信你會學會如何構建你的lib,看看在GAlib中已經做了什麼。

1

從我的一部分。一些隨機位:

  • 你應該檢查(作爲方法)的一個項目是watchmaker
  • 建設氣體的最難的是找到問題的一個明智的基因表達並建立一個健身功能與良好的分配健身對於給定的人口
  • 當處理(米)任何硬約束,你可以考慮引入一個翻譯 (可能)垃圾DNA和一點性能的代價
0

正如人們所說,不要讓它成爲一個巨人類。那太可怕了。封裝不同類別的行爲。策略是一個解決方案。
如果您需要示例下載源和JGAP的示例。它支持遺傳編程和遺傳算法。你會看到不錯的漂亮設計。突變,交叉,選擇,人口,基因 - 所有這些都是單獨的類。您只需設置Configuration對象,在其中啓動要使用的實現的已定義接口,並傳遞適當的算法參數並運行它。真正的包是巨大的,javadoc很好,你可以隨時查看源代碼或檢查郵件組的某些答案。當我在尋找GA包時,我看到GAlib和其他人,但我認爲這是一個非常完美的設計。

2

實現我的GA框架是如下時,我採取的方法: 創建以下類別: 代 GeneticAlgorithm GeneticAlgorithmAdapter GeneticAlgorithmParameters 人口 個人

雖然我沒有實現的戰略模式各種操作,我確信在GeneticAlgorithm實例上創建各種GA操作實現作爲參數是微不足道的。

GeneticAlgorithm類捕獲基本算法。它確實定義了各種步驟(人口創建,個體隨機化,選擇,交叉,變異等),並在算法運行時管理個體的種羣。我想如果你想的話,你可以在這裏插入不同的操作。

真正的魔力在於適配器。這是將問題域(個人的具體子類及其所有相關數據)適用於遺傳算法。我在這裏大量使用泛型,以便將具體類型的人口,參數和個人傳遞到實現中。這使我能夠對適配器的實現進行智能感知和強類型檢查。適配器基本上需要定義如何執行給定個體(及其基因組)的特定操作。例如,下面是適配器接口:

/// <summary> 
/// The interface for an adapter that adapts a domain problem so that it can be optimised with a genetic algorithm. 
    /// It is a strongly typed version of the adapter. 
    /// </summary> 
    /// <typeparam name="TGA"></typeparam> 
    /// <typeparam name="TIndividual"></typeparam> 
    /// <typeparam name="TPopulation"></typeparam> 
    public interface IGeneticAlgorithmAdapter<TGA, TIndividual, TGeneration, TPopulation> : IGeneticAlgorithmAdapter 
     where TGA : IGeneticAlgorithm 
     where TIndividual : class, IIndividual, new() 
     where TGeneration : class, IGeneration<TIndividual>, new() 
     where TPopulation : class, IPopulation<TIndividual, TGeneration>, new() 
    { 
     /// <summary> 
     /// This gets called before the adapter is used for an optimisation. 
     /// </summary> 
     /// <param name="pso"></param> 
     void InitialiseAdapter(TGA ga); 

     /// <summary> 
     /// This initialises the individual so that it is ready to be used for the genetic algorithm. 
     /// It gets randomised in the RandomiseIndividual method. 
     /// </summary> 
     /// <param name="ga">The genetic algorithm that is running.</param> 
     /// <param name="individual">The individual to initialise.</param> 
     void InitialiseIndividual(TGA ga, TIndividual individual); 

     /// <summary> 
     /// This initialises the generation so that it is ready to be used for the genetic algorithm. 
     /// </summary> 
     /// <param name="ga">The genetic algorithm that is running.</param> 
     /// <param name="generation">The generation to initialise.</param> 
     void InitialiseGeneration(TGA ga, TGeneration generation); 

     /// <summary> 
     /// This initialises the population so that it is ready to be used for the genetic algorithm. 
     /// </summary> 
     /// <param name="ga">The genetic algorithm that is running.</param> 
     /// <param name="population">The population to initialise.</param> 
     void InitialisePopulation(TGA ga, TPopulation population); 

     void RandomiseIndividual(TGA ga, TIndividual individual); 

     void BeforeIndividualUpdated(TGA ga, TIndividual individual); 
     void AfterIndividualUpdated(TGA ga, TIndividual individual); 

     void BeforeGenerationUpdated(TGA ga, TGeneration generation); 
     void AfterGenerationUpdated(TGA ga, TGeneration generation); 

     void BeforePopulationUpdated(TGA ga, TPopulation population); 
     void AfterPopulationUpdated(TGA ga, TPopulation population); 

     double CalculateFitness(TGA ga, TIndividual individual); 

     void CloneIndividualValues(TIndividual from, TIndividual to); 

     /// <summary> 
     /// This selects an individual from the population for the given generation. 
     /// </summary> 
     /// <param name="ga">The genetic algorithm that is running.</param> 
     /// <param name="generation">The generation to select the individual from.</param> 
     /// <returns>The selected individual.</returns> 
     TIndividual SelectIndividual(TGA ga, TGeneration generation); 

     /// <summary> 
     /// This crosses over two parents to create two children. 
     /// </summary> 
     /// <param name="ga">The genetic algorithm that is running.</param> 
     /// <param name="parentsGeneration">The generation that the parent individuals belong to.</param> 
     /// <param name="childsGeneration">The generation that the child individuals belong to.</param> 
     /// <param name="parent1">The first parent to cross over.</param> 
     /// <param name="parent2">The second parent to cross over.</param> 
     /// <param name="child">The child that must be updated.</param> 
     void CrossOver(TGA ga, TGeneration parentsGeneration, TIndividual parent1, TIndividual parent2, TGeneration childsGeneration, TIndividual child); 

     /// <summary> 
     /// This mutates the given individual. 
     /// </summary> 
     /// <param name="ga">The genetic algorithm that is running.</param> 
     /// <param name="generation">The individuals generation.</param> 
     /// <param name="individual">The individual to mutate.</param> 
     void Mutate(TGA ga, TGeneration generation, TIndividual individual); 

     /// <summary> 
     /// This gets the size of the next generation to create. 
     /// Typically, this is the same size as the current generation. 
     /// </summary> 
     /// <param name="ga">The genetic algorithm that is running.</param> 
     /// <param name="currentGeneration">The current generation.</param> 
     /// <returns>The size of the next generation to create.</returns> 
     int GetNextGenerationSize(TGA ga, TGeneration currentGeneration); 


     /// <summary> 
     /// This gets whether a cross over should be performed when creating a child from this individual. 
     /// </summary> 
     /// <param name="ga">The genetic algorithm that is running.</param> 
     /// <param name="currentGeneration">The current generation.</param> 
     /// <param name="individual">The individual to determine whether it needs a cross over.</param> 
     /// <returns>True to perform a cross over. False to allow the individual through to the next generation un-altered.</returns> 
     bool ShouldPerformCrossOver(TGA ga, TGeneration generation, TIndividual individual); 

     /// <summary> 
     /// This gets whether a mutation should be performed when creating a child from this individual. 
     /// </summary> 
     /// <param name="ga">The genetic algorithm that is running.</param> 
     /// <param name="currentGeneration">The current generation.</param> 
     /// <param name="individual">The individual to determine whether it needs a mutation.</param> 
     /// <returns>True to perform a mutation. False to allow the individual through to the next generation un-altered.</returns> 
     bool ShouldPerformMutation(TGA ga, TGeneration generation, TIndividual individual); 
    } 

我發現,這種方法很好地工作適合我,因爲我可以很容易地重用GA實施不同的問題域,僅僅是寫在相應的適配器。就不同的選擇,交叉或變異實現而言,適配器可以調用它感興趣的實現。當我正在研究適當的策略時,我通常會做的是在適配器中註釋不同的想法。

希望這會有所幫助。我可以在必要時提供更多指導。做這樣的設計公正很難。