-- |-- Routines for selection after fitness evaluation. Selection is the process-- of taking some input population P, a set of fitness values such that-- each p in P has a fitness score f(p,X) under some fitness test X, and-- selecting which members of P participate in the creation of the next-- population P'.---- A common technique is roulette wheel selection. In essence, this means that-- we create a roulette wheel with one slot per individual where the width of-- each slot is a function of the fitness of the individuals. So, those-- individuals with very good fitness will have wide slots and a correspondingly-- high likelihood of selection, while poor fitness individuals will have tiny-- slots and a low probability of being selected.---- Fitness testing takes place outside this module. This module is only-- concerned with the selection process (ie: generating the roulette wheel).---- Author: mjsottile\@computer.org--moduleGEP.Selection(generate_roulette_weights,roulette,selector,getBest)whereimportGEP.TypesimportGEP.RmonadimportList(sort){-|
Given a set of pairs (f,i) where f is the fitness of the individual i,
return the pair representing the individual with the best fitness.
We may return nothing if an empty set is passed in to begin with, so
the return type is a Maybe pair.
-}getBest::[(Double,Individual)]-- ^ Fitness/Individual pairs->Maybe(Double,Individual)-- ^ Best pair, or Nothing if no such pairgetBest[]=NothinggetBestindividuals=letinnerBest[]bibf=Just(bf,bi)innerBest((f,i):rest)bibf=iff>bftheninnerBestrestifelseinnerBestrestbibf(firstB,firstI)=headindividualsininnerBest(tailindividuals)firstIfirstBweight_function::Double->Double->Doubleweight_functionne=1.0/(n**e){-|
Given a list of indices and a list of data elements, create a new list
of data elements composed of the elements listed in the index list.
The output list may contain duplicates.
-}selector::[Int]-- ^ List of indices to select->[a]-- ^ List of elements ->[a]-- ^ List composed of elements selected from original set by indices providedselectorix=reverse(innerSelect0(sorti)x[])-- tail recursive version of inner selectinnerSelect::Int->[Int]->[a]->[a]->[a]innerSelect_[]_l=linnerSelect__[]l=linnerSelectn(i:is)(x:xs)l=if(i==n)theninnerSelectnis(x:xs)(x:l)elseinnerSelect(n+1)(i:is)xsl{-|
Generate n roulette weights with a generator exponent e. A helper function
weight_function is used to generate the actual weights. For example,
w = (k^e)^(-1) for k from 1 to n leads to a set of weights such that the
size of the slots decreases exponentially as fitness decreases. When e=1,
this decrease is linear. The list that is returned is the width of each slot
such that the total of the weights adds to 1.0.
-}generate_roulette_weights::Double->Double->[Double]generate_roulette_weightsne=map(\i->i/sx)weightswhereweights=[weight_functionxe|x<-[1..n]]sx=foldr(+)0.0weights{-|
Given a set of roulette weights and a number of spins of the wheel, return
a list of indices corresponding to the winning slot for each spin. This
is used to perform the actual selection after a set of roulette weights are
generated.
-}roulette::[Double]->Int->GEPMonad[Int]roulette_0=doreturn[]rouletteweightsn=doval<-nextF1.0rest<-rouletteweights(n-1)return([find_bin0.00valweights]++rest)wherefind_bin_m_[]=mfind_bintotmval(b:bs)=if(val>tot)&&(val<=(tot+b))thenmelsefind_bin(tot+b)(m+1)valbs