| |||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||
Diophantine Equation Solver
This is a C++ program that solves a diophantine equation using genetic algorithms. This is the first program is a new set of programs popping up on Generation5 - case studies. Therefore this page is a huge break down of the code and what it does, how it does it, and how to use it. Without further ado, here is the download link: diophantine.zip (3.12k). This code is the accompanying code to the genetic algorithms example, so please read that if you don't know anything about GAs before attempting to look at this code. Trust me, Sam wrote the essay, and I learnt and coded the program straight from what I learnt from that essay - its great! Now for the code:
CDiophantineFirstly the class header (note for formatting reasons, a lot of the documentation is taken out):Firstly you notice that there are two structures, the gene structure and the actual CDiophantine class. The gene structure is used to keep track of the different solution sets. The population generated is a population of genes. The gene structure keeps track of its own fitness and likelihood values itself. I also coded a small function to test for equality, this just made some other code a lot more concise. Now onto the functions.#include <stdlib.h> #include <time.h> #define MAXPOP 25 struct gene { int alleles[4]; int fitness; float likelihood; // Test for equality. operator==(gene gn) { for (int i=0;i<4;i++) { if (gn.alleles[i] != alleles[i]) return false; } return true; } }; class CDiophantine { public: CDiophantine(int, int, int, int, int); int Solve(); // Returns a given gene. gene GetGene(int i) { return population[i];} protected: int ca,cb,cc,cd; int result; gene population[MAXPOP]; int Fitness(gene &); void GenerateLikelihoods(); float MultInv();inverse. int CreateFitnesses(); void CreateNewPopulation(); int GetIndex(float val); gene Breed(int p1, int p2); };
Fitness function
Note that if the fitness is zero, then a solution has been found - so return the index. After we calculate the fitnesses, we then have to calculate the likelihoods of the gene's being chosen.
Likelihood functions
In my program though, with the same initial values, the likelihoods would be cumulatively added - imagine it like the percentage of a pie chart. The first gene is from 0 to 8.80%, the next goes to 39.6% (because it starts from 8.8). The likelihood table would look like this:
The last value will always be 100 (in the above example, it isn't due to rounding). Now with the theory of it, let's look at the code. The code is very simple - note though that a type cast to float is required on the fitness value so that integer division doesn't occur. There are two functions, one to calculate the smi, and another to generate all the likelihoods.
Ok, so now that we have the fitness and likelihoods values all set up, it's time to do some breeding!
Breeding Functions
So, we firstly create a temporary population of genes. Then we loop through all the genes. Now, when choosing genes we don't want the genes to be the same (no point mating with yourself :), and we don't need the genes to be the same either (that is where the operator== from the gene structure comes in handy). In choosing a parent, we generate a random number, then call the GetIndex function. GetIndex uses the idea of the cumulative likelihoods and merely iterates through the genes until it find the gene that contains that number:
Returning to the CreateNewPopulation() function, you can also see that if the number of iterations exceeds MAXPOP squared, it will take any parents. After parents are chosen, we breed them, by passing the indices up to the Breed function. The Breed function returns a gene, which is put in the temporary population. Here's the code:
Firstly we determine the crossover point. Now remember, we don't want the crossover to be the first or the last, because that entails copying over all or none of the second parent - pointless. We then create a random number that will determine when the first parents takes the initial crossover or not. The rest is self-explanatory - you can see that I've added a tiny mutation factor to the breeding. There's a 5% chance that a new number will occur.
And finally...
So there you have it - the full explanation. An example of how to use the class can be found at the bottom of the example essay. I'm sure this code is 100% ANSI C++ - if it is not, and you have trouble compiling it, please contact me.
Submitted: 14/02/2000 Article content copyright © James Matthews, 2000.
|
|
||||||||||||||||||||||||||||||||
All content copyright © 1998-2007, Generation5 unless otherwise noted.
- Privacy Policy - Legal - Terms of Use -