- Aldo Gonzalez
4/19 Selection, Mutation, Crossover, and Initial Cycle Runs!
Done:
It turns out I didn't have to worry about index-searching methods, such as linear or hash. I just had to set a fitness score property to each population list so that the sorting and selection can happen with the tiles themselves, rather than with the fitness scores, which need to be correlated with the tiles. To do this, I found a class "L" that takes a list and allows for property additions, and I made all population lists Ls.
Here is a drawing of the index-based approach of a cycle. My current approach is the same, with the removal of the fitness list and the final list being Gen. I plan to take a generation (after each population gets a fitness score) and make two copies for the selection process. The first is sorted and runs some elitism code to pick out the best ones; those are thrown into Gen (which is cleared before this). The second has the bracket algorithm run through it, taking half of them into Gen. Mutation and crossover run here next. Lastly, the Gen items are shuffled using the Python random library. Now the next generation is ready!
I did my elitism and bracket selection code. I also did mutation code. I have it changing one tile, but that was enough to make some significant changes in one cycle.
I had an issue with globals in Python. Globals are strange there, which reminds me of JavaScript. But I got through that.
I also got crossover working! The fourth members are a mix of members 1 and 2 (initially hard-coded for testing). The function makes a copy of a random member, appends it to the end of Gen, picks out another random member, and takes every other row from there into the new member.
To have a better visual representation, I thought new images were in order. Dr. Pankratz gave the idea of a Mona Lisa, or something easier to tell, instead of having to look at the original image. Here are my latest ones.
Finally, I set my cycle up! It took some conceptual integrity working, such as deciding to use tilesList as a temp, deciding that the initial loop in randomT is needed for set-up (i.e., it is unique and need only run once) and having the fitness function take Gen members.
Below are some initial attempts. All used only 4 populations with varying amounts of cycles. The first few had 300 cycles and took 4 minutes, consuming some CPU but no RAM. The third had 1000 cycles and took 10 minutes. I was amazed that it really works! This genetic algorithm stuff is legitimate, after all! It's also great to know the finish line is in sight!
Note: perfection is now 3750 (I changed the sizing).
Several characters are in the right place!
If you don't look too closely at the second one, it looks like only two tiles are wrong!
Next Steps:
Of course, 4-10 minutes is a long time, and we're still somewhat far from perfection (which can probably be achieved in these cases). I need to do a handful of things next.
crossover visual testing (I forgot to check if it's doing exactly what I want it to do)
add shuffle at the end of the cycle
test with more populations and fewer cycles (my guess is it will not only get better, but it will be done faster due to the diversity helping the algorithm)
more tiles
average tile color fitness function (this can go super fast and probably perform just as well for these basic cases. It may also be a good secondary algorithm to show for advanced cases)