Tuesday 2 January 2018

Mating Sudoku

Natural Selection: the process whereby organisms better adapted to their environment tend to survive and produce more offspring.

Given that this age-old strategy of cultivating the fit and eliminating the weak has shaped everything from predatorial leopards to the complexity of human brains, it'd be safe to assume that it too could be employed to undertake menial tasks for lazy people, say, solve a sudoku for me. Right?

Well, let's give it a try!

Now the first step would be to understand the mechanisms of evolution. According to Wikipedia, there are 4 major aspects that concern the evolution of species in the natural world. 
1. Population
2. Sex & Recombination
3. Mutation
4. Selection

Step 1: Population


For natural selection and evolution to work, we first need to start with an initial population. In the case of my sudoku-solving quest, I will have to start with a randomized solution that fills up the sudoku puzzle. 

First, I load up a problem set as demonstrated to the left. Then, the program generates a list of 15 randomized solution, as shown below:

Alright, that fulfills the step one of evolution. As you can see from the solution above, there are many violations to the sudoku rule, such as repeating digits in the same row/column or in the same 3x3 tile. We need to start pairing these random solutions with each other to produce offsprings that fare better than their randomized parents.




Step 2: Sex & Recombination

Here comes the fun part. To decide which pairs of randomized solutions get to 'mate' with each other and produce combined results, I opted to learn from nature. As natural selection prefers organisms with higher fitness index, I had to introduce an artificially-conceived Fitness Index to differentiate between the population. 

This is how the fitness index is calculated:

TL;DR: I took the maximum fitness score (243) and subtract 1 for every time a tile violates the row/column/tile non-repetition rule. So a row with the digits 6,5,6,4,9,1,2,1,6 would lead to deduction of 3 scores due to repeating 6s and 1s

Whew. Now that we got that sorted, let's see just how fit our first generation of sudoku solutions are. 

A whopping 92/243! That's horrible, and as you can tell from how the numbers are arranged, there are so many errors and repetitions and digits across rows and columns.

Luckily, we don't have to panic yet. Despite starting off as blind and deaf unicellular organisms, we ended up faring pretty well after billion years of evolution. What we need is for our ancestors to have ample time and a lot of sex. A whole lot of 'em.

Cross-over mechanism:
1. Lottery to pick 2 sudoku-solutions for sexual reproduction(Chances are weighed by their Fitness Index)
2. Convert solution tables from both parties into lists of numbers. Then split the list of numbers at a randomized position and join the two lists together
3. Convert the joined list back into table form
4. A new baby is born

(For detailed understanding of the mechanism, refer to lines 41-67 in the source code)

Step 3: Mutation

If the population were left to intermix with each other, they will gradually converge into identical copies over time. Unless you are a fan of the dystopian clone-ridden future, we need to prevent this situation from occurring. If our sudoku-solutions were to converge too quickly, we will end up with suboptimal solutions with no room for improvement.

A working contingency plan, as demonstrated by nature, is to create random mutations. In nature, this happens because of DNA cloning errors. In the program, we artificially induce mutations on random tiles on the table.  





Note that mutation is not always good for the offspring. In 80% of the case, the mutation will lead to disastrous results, causing the offpsrings to shed off 20-30 fitness score. In the long run, mutation does lead to better diversity and more potential for growth.

 Step 4: Selection

This step is made easy for us. All sudoku solutions simply die off (or shall I say, executedafter each iteration. Their evolutionary success is judged solely by their reproductive ability, and that in turns is artificially determined by their Fitness Index. (Step 2)

With all four steps set in place, let's run our program!



As you can see, the average fitness and best fitness indexes are slowly climbing up after multiple generations of recombination and selection.

The process starts to slow down after 2-3 minutes as individuals of the population become more and more similar to each other. Here's the results after 4 hours of the repeated process, as taken from my previous run:



Pretty neat, eh? Admittedly, there's still room for improvements, as the solution hasn't reached the optimal solution of 240. For that to happen, better algorithms is needed, as my program hits a plateau at around the 200 region and never seemed to go over it.

Hope you enjoyed the read. All ideas and suggestions are greatly welcomed!

Source Code (Python): https://github.com/ImSandwich/AI-Code-Projects/blob/master/genetic.py

To test the code for yourself:
1. Download and install Python 3.6.x from https://www.python.org/downloads/
2. Download the source code
3. Open up Command Prompt
4. type cd [the folder you downloaded the source code to]
For example: C:\Users\User\Desktop\Code Projects\
5. type python genetic.py
6. Insert the desired population size (Recommended: 15)
7. Insert the desired mutation rate (Recommended: 0.04)
8. Insert the desired cutoff  (Recommended: 60, this is the minimum fitness a solution must have to be considered for survival)
9. Insert the desired scatter rate (Recommended: 0.15, this is a simulation of natural disasters that will occur leading to random selection of population)
10. Let it run, set back and enjoy =)

Imitation Game

Think of a number in your head. It could be anything from 0-9. Got it? Good.

Now let me guess what number it is.

First, I'll present you with ten random numbers. They are 3,3,1,4,9,7,8,4,3,1






Did the number on your mind appear in the list? Shout out '1' if it did!
It didn't? Oh well, reply with a '0' instead then.

Let's take a number for demonstration. We'll go with 5 as it didn't appear on the list. In accordance to the rule, at no time should I reveal the number on my mind, but instead let my computer figure it out on its own by feeding it '1's (if my numbers appeared in abundance) or '0's (if it did not)


I chose to input 0 on the first entry as my desired number did not appear on the list. Immediately on the second list we see the number '5' popping up.


By encouraging the computer with '1's when the number 5 is in abundance, it took the hint and increased its preference towards the number

The dominant guesses are now between 4 and 5


4s seems to slowly overtake 5s, so I fed it with a '0' as I am not satisfied with the computer's divided guess. On the following list, we can see the computer went with the number 5.




Slowly, by rewarding/punishing my computers with 1s(which it likes) and 0s(which it tries to avoid), it made out my intention and guessed the number 5.

Voila! A program that knows what's on your mind. Granted it is not the brightest at the game, and requires an average 15-20 inputs to arrive at an accurate guess, but nevertheless this simple app demonstrated an inherent ability to learn and adapt to the user's input.

Here's my goal: To keep the number of guesses down to 5-10. I'll keep you posted when I stumble upon an algorithm that allows for that level of quick learning.

Source Code (Python): https://github.com/ImSandwich/AI-Code-Projects/blob/master/learning_agent.py

To test the code for yourself, simply:
1. Download and install Python 3.6.x from https://www.python.org/downloads/
2. Download the source code
3. Open up Command Prompt
4. type cd [the folder you downloaded the source code to]
For example: C:\Users\User\Desktop\Code Projects\
5. type python learning_agent.py

Enjoy! All feedback and suggestions for improvement is greatly welcomed =) Peace out.