Algorithm Description:
- Examine each gene's ability to solve problems and quantify this ability
- Select the gene in the current memory as the parent. The choice principle is: the greater the ability to solve the higher the probability of the choice.
- The two selected hybrids are hybridized according to the hybridization rate, generating offspring
- Mutation of offspring based on mutation rate
- Repeat 2, 3, 4, until the new generation has finished.
Now you need to use this algorithm to solve the following pathfinding problems:
There is a randomly generated maze, in which a starting point and a focus are identified, finding a heavy starting point to the point of access.
Similar problem solving methods are no longer mentioned here, just try to use genetic algorithm to solve.
The basic idea is to encode the solution as a gene and then, through the evolution of the genetic algorithm, find a solution or approximate solution.
Solve the problem:
The encoding is as follows:
Action in the maze only up and down four kinds, with two-bit 2 encoding exactly right
The next step is to quantify a genetic problem-solving capability, which is measured by the "lattice distance to the end", which is:
DIFFX = end_point.x-= end_point.y-y
Here's the X/y so sure:
If the progression of a gene goes to a dead end (that is, a wall), then the current X/y is taken, and the effective length of the gene stops there.
I define the following genetic classes:
LocalGenome = {}functiongenome:new (len)Localn \{} o.bits={} o.fitness=0 --Math.randomseed (Os.time ()) fori =1Len Do if Math.random() >0.5 Then Table.insert(O.bits,1) Else Table.insert(O.bits,0) End End returnoEndreturnGenome
Initialize a gene pool, this is the first generation, the content of the gene is random, the length is set to the appropriate value, the size of the library is recommended for twice times the length of the gene.
Set the first generation, we need to determine the ability of each gene, we use the following value to represent:
1/(diffx+diffy+1)
The addition of 1 is to prevent the denominator from being zero.
Then we began to choose the parent to reproduce, and we knew that hybridization and mutation would not determine the evolutionary direction of the whole population, and that the significant responsibility for the direction fell on the choice of this step (consider nature as a truth)
Here in order to meet the said "the greater the ability to solve the higher the probability of the choice" principle, the simple use of the betting wheel selection method, and the same as the roulette wheel, the bigger the disc above the area of the ball stop in which the probability is greater.
--Betting Wheel SelectionfunctionTest1:Select() Localpiece =Math.random()*self.total_fitnessLocaltemp =0 forI=1, #self. Genomes DoTemp= temp +self.genomes[i].fitnessifTemp>=piece Then returnSelf.genomes[i]End EndEnd
Select the parent in the population by betting round and then cross:
Hybridization is that if you meet the hybridization conditions (which are controlled by hybridization here), randomly select a hybridization point that randomly identifies a point on the gene, swapping all previous fragments, and keeping the subsequent fragments intact.
If the hybridization condition is self-crossing or not satisfied, the parent is sent directly to the offspring.
--hybridization--return Arraysfunctiontest1:crossover (dad,mum)LocalChild1 = {} LocalChild2 = {} LocalRN =Math.random() ifRn<self.crossover_rate Then LocalPT =Math.random(#dad) forI=1, pt-1 DoChild1[i]=Dad[i] Child2[i]=Mum[i]End forI=PT, #dad DoChild1[i]=Mum[i] Child2[i]=Dad[i]End ElseChild1=dad Child2=mumEnd returnchild1,child2End
Then, the mutation rate is predetermined, and only the offspring gene fragment that satisfies the mutation rate will mutate, and the mutation mode takes the direct flip fragment.
--mutationfunctiontest1:mutate (BITS) forI=1, #bits Do if Math.random() <self.mutation_rate Then ifbits[i]==1 ThenBits[i]=0 ElseBits[i]=1 End End EndEnd
Then perform the above steps for the entire population, knowing that the new generation is complete.
Here is waiting for the offspring to replace the next generation, and I am not sure what will happen if we take the new generation directly to replace some of the weaker individuals in the current generation.
Here is the Evolution code:
--Evolutionfunctiontest1:step_in ()Self:detect_map ()LocalAll_chids_n =0 whileAll_chids_n < SELF.GN Do --Test MapSelf:detect_map ()LocalDad = Self:Select() LocalMum = self:Select() --Create a new descendant LocalChild1 =genome:new (SELF.GL)LocalChild2 =genome:new (SELF.GL)--hybridizationChild1.bits, child2.bits =self:crossover (dad.bits, mum.bits); --mutationself:mutate (child1.bits); Self:mutate (child2.bits); --inserted into the new gene pool, the new gene pool is full of changes that indicate a generation Table.insert(Self.new_genomes, Child1)Table.insert(Self.new_genomes, child2) all_chids_n= All_chids_n +2 EndSelf.genomes=self.new_genomes self.new_genomes= { } --number of records generationSelf.ig = Self.ig +1End
Now everyone is waiting for the "king" to appear.
The condition of the "king" is simple: as long as he succeeds in reaching the end.
if diffx+diffy<=2then -Interrupt Evolution output current gene end
Then, look at the running results of the program:
I used the 20x20 map size, randomly added some obstacles, the console below the program shows the entire attempt took 42 generations of evolution.
It is important to note that this algorithm is inherently time-consuming, and I use LUA to simulate, the speed is much slower than C + +, so a 20x20 map to find a solution of the time is often quite long, and sometimes may not find the solution. In order not to allow the entire program to wait indefinitely, I limit the entire population can only evolve 200 generations, more than this number is considered to be no solution to this problem, if you use the upload program, you can click the middle mouse button to restart the entire simulation. In addition, if the luck is not very good, find a group of solutions will tend to be quite long, the whole program looks like the crash, the only thing to do is to wait, if the program return to normal response usually indicates that a group of solutions have been found, this time a small zombie will go along this path from the beginning to the end.
All parameters of the program can be modified within the Test1.lua.
Finally, in order to prevent random gene from doing some meaningless reverse action (that is, the previous step to the left to go to the right), I banned and fixed these behaviors:
ifBit1 = =0 andBit2 = =1 Then ifSelf.no_back Then ifbith1==1 andBith2 = =1 Theny= y-1Gs[i].bits[j]=1gs[i].bits[j+1] =1 Elsey= y +1 End Elsey= y +1 End
End
Code
Genetic algorithm Learning (solving pathfinding problems)