Last active
September 4, 2018 00:09
-
-
Save davidcairuz/7660d8280223b70a9cdec899374883de to your computer and use it in GitHub Desktop.
Genetic Algorithm approach to the Knapsack problem in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <bits/stdc++.h> | |
using namespace std; | |
char** create_pop(int pop_size, int numberOfObj) { | |
char** population = (char**) malloc(pop_size * sizeof(char*)); | |
// creates a 'numOfObj' sized string for each position in the population vector | |
for(int i = 0; i < pop_size; i++) { | |
population[i] = (char*) malloc((numberOfObj + 1) * sizeof(char)); | |
} | |
srand(time(NULL)); | |
for(int i = 0; i < pop_size; i++) { | |
// randomly decides which letter will be in a determined position | |
for(int j = 0; j < numberOfObj; j++) { | |
// letter may be either 0 or 1 | |
// 1 means the object was taken | |
char letter = (rand() % 2) + '0'; | |
population[i][j] = letter; | |
} | |
// adds string terminator in the end of each individual (don't know if this is necessary) | |
population[i][numberOfObj] = '\0'; | |
} | |
return population; | |
} | |
void evaluate(char** population, int pop_size, int numberOfObj, int maxWeight, const vector< pair<int, int> >& objects, int** fitness) { | |
// for each individual | |
for(int i = 0; i < pop_size; i++) { | |
int fit = 0; | |
int weight = 0; | |
for(int j = 0; j < numberOfObj; j++) { | |
if(population[i][j] == '1') { | |
// add up the fit and weight of the correspondent object | |
fit += objects[j].first; | |
weight += objects[j].second; | |
} | |
} | |
// sets fitness to 0 if weight is above maximum | |
if (weight > maxWeight) (*fitness)[i] = 0; | |
else (*fitness)[i] = fit; | |
} | |
} | |
void crossover(char*** population, int pop_size, int numberOfObj, char* best, int bestIdx) { | |
char letter; | |
for(int i = 0; i < pop_size; i++) { | |
// making sure we don't change the best individual | |
if (i == bestIdx) { | |
continue; | |
} | |
// a gene may come from the best individual or from the individual we're crossovering now | |
for(int j = 0; j < numberOfObj; j++) { | |
int choose = rand() % 2; | |
// if choose equal 0, gene comes from the best | |
// otherwise, gene comes from the current individual | |
if(choose == 0) { | |
letter = best[j]; | |
} else { | |
letter = (*population)[i][j]; | |
} | |
// changes the current letter into the chosen one | |
(*population)[i][j] = letter; | |
} | |
(*population)[i][numberOfObj] = '\0'; | |
} | |
} | |
void mutation(char*** population, int pop_size, int numberOfObj, int bestIdx, int mutationTax) { | |
int numOfChanges = (mutationTax / 100) * numberOfObj; | |
if (numOfChanges == 0) { | |
numOfChanges = 1; | |
} | |
for(int i = 0; i < pop_size; i++) { | |
// making sure we don't mutate the best individual | |
if(i == bestIdx) continue; | |
// the 'numOfChanges' is based on the 'mutationTax' but is at least 1 | |
for(int j = 0; j < numOfChanges; j++) { | |
// randomly chooses a letter to invert | |
int choose = rand() % numberOfObj; | |
if( (*population)[i][choose] == '1') (*population)[i][j] = '0'; | |
else (*population)[i][choose] = '1'; | |
} | |
} | |
} | |
// this function kills all the individuals with 0 fitness and generate a random one in its place | |
void genocide(char*** population, int pop_size, int numberOfObj, int* fitness) { | |
for(int i = 0; i < pop_size; i++) { | |
if (fitness[i] == 0) { | |
for(int j = 0; j < numberOfObj; j++) { | |
char letter = (rand() % 2) + '0'; | |
(*population)[i][j] = letter; | |
} | |
(*population)[i][numberOfObj] = '\0'; | |
} | |
} | |
} | |
void free_all(char*** pop, int pop_size, int numberOfObj, int** fitness) { | |
for(int i = 0; i < pop_size; i++) { | |
free((*pop)[i]); | |
} | |
free(*pop); | |
free(*fitness); | |
} | |
int main() { | |
vector< pair<int,int> > objects; // stores all values and weights of objects | |
char** population; // contains strings of 0s and 1s representing each individual | |
int value, weight; // stores value and weight of a object | |
int mutationTax = 5; // hardcoded mutation tax | |
int numberOfObj; // stores number of objects (also size of string) | |
int maxWeight; // stores the maximum capacity of the backpack | |
int* fitness; // will store the fitness of each individual | |
int pop_size; // stores population size | |
int bestIdx; // stores the index of the best individual | |
char* best; // stores the string that represents the best individual | |
printf("Enter population size: "); | |
scanf("%d", &pop_size); | |
printf("Enter maximum weight: "); | |
scanf("%d", &maxWeight); | |
printf("Enter the number of objects: "); | |
scanf("%d", &numberOfObj); | |
printf("Write all the objects below (value, weight):\n"); | |
for(int i = 0; i < numberOfObj; i++) { | |
cin >> value >> weight; | |
objects.push_back(make_pair(value, weight)); | |
} | |
// creates first population | |
population = create_pop(pop_size, numberOfObj); | |
// creates fitness vector | |
fitness = (int*) malloc(pop_size * sizeof(int)); | |
int stuck = 0; // used to check since when the best fitness is stuck | |
int dynamicMut = 0; // used to change mutation tax after being stuck for a while | |
bool mutationFlag = false; // used to decide if we're going to increase or decrease the mutation tax | |
int lastFit = 0; // used to compare fitness and increase 'stuck' | |
while(true) { | |
evaluate(population, pop_size, numberOfObj, maxWeight, objects, &fitness); | |
bestIdx = max_element(fitness, fitness + pop_size) - fitness; | |
best = population[bestIdx]; | |
int bestFit = fitness[bestIdx]; | |
// if we are stuck, increase dynamicMut and 'stuck' | |
// and if the fitness has changed, set 'stuck' and 'dynamicMut' to 0 | |
if(bestFit == lastFit) { | |
dynamicMut++; | |
stuck++; | |
} else { | |
dynamicMut = 0; | |
stuck = 0; | |
} | |
printf("The current mutation tax is: %d\n", mutationTax); | |
printf("The best pick is %s | Fitness: %d\n", best, bestFit); | |
for(int i = 0; i < pop_size; i++) { | |
printf("Individual %d: %s | Fitness: %d\n", i+1, population[i], fitness[i]); | |
} | |
printf("\n"); | |
crossover(&population, pop_size, numberOfObj, best, bestIdx); | |
// the block of code below can be changed to achieve better results | |
if(dynamicMut > 50 and mutationFlag == false) { | |
mutationTax = 25; | |
mutationFlag = true; | |
dynamicMut = 0; // after changing the mutation tax we set only 'dynamicMut' back to 0, not 'stuck' | |
} else if(dynamicMut > 150 and mutationFlag == true) { | |
mutationTax = 5; | |
mutationFlag = false; | |
dynamicMut = 0; | |
} else if(stuck > 500) break; | |
mutation(&population, pop_size, numberOfObj, bestIdx, mutationTax); | |
genocide(&population, pop_size, numberOfObj, fitness); | |
// saving fitness of current generation | |
lastFit = fitness[bestIdx]; | |
} | |
free_all(&population, pop_size, numberOfObj, &fitness); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 | |
6404180 | |
24 | |
825594 382745 | |
1677009 799601 | |
1676628 909247 | |
1523970 729069 | |
943972 467902 | |
97426 44328 | |
69666 34610 | |
1296457 698150 | |
1679693 823460 | |
1902996 903959 | |
1844992 853665 | |
1049289 551830 | |
1252836 610856 | |
1319836 670702 | |
953277 488960 | |
2067538 951111 | |
675367 323046 | |
853655 446298 | |
1826027 931161 | |
65731 31385 | |
901489 496951 | |
577243 264724 | |
466257 224916 | |
369261 169684 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 | |
170 | |
7 | |
442 41 | |
525 50 | |
511 49 | |
593 59 | |
546 55 | |
564 57 | |
617 60 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment