-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenetic_grouping.cpp
More file actions
318 lines (259 loc) · 9.79 KB
/
genetic_grouping.cpp
File metadata and controls
318 lines (259 loc) · 9.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#include<bits/stdc++.h>
#define POPULATION_SIZE 6
using namespace std;
struct Chromosome{
vector<vector<int>> groups; //starting index for group number is 0
vector<int> genes; //store group number of r-th student
int fitness_score; //store fitness-value
};
typedef struct Chromosome Chromosome;
struct Population{
vector<Chromosome> chromosomes;
};
typedef struct Population Population;
//Variables declaration
Population population; //to store population
vector<int> marks; //input marks for a student -> sum -> insert into marks vector
int no_of_students, no_of_subjects, no_of_groups;
int fitness_count = 0;
int lowestTotalFitness = INT_MAX;
Chromosome fittest;
void input(){
cout << "Enter number of students: ";
cin >> no_of_students;
cout << "Enter number of subjects: ";
cin >> no_of_subjects;
cout << "Enter number of groups: ";
cin >> no_of_groups;
cout << endl;
for (int i = 0; i < no_of_students; ++i)
{
cout << "Enter marks of student " << i + 1 << ": ";
int temp_marks;
int temp_total = 0;
for (int j = 0; j < no_of_subjects; ++j)
{
cin >> temp_marks;
temp_total += temp_marks;
}
int avg = temp_total / no_of_subjects;
marks.push_back(avg);
}
}
int randomGroup(){
//min is 0
return rand() % no_of_groups;
}
int square(int n){
return n * n;
}
void calculateFitness()
{
cout << "\n=>Calculate fitness\n";
for (int i = 0; i < population.chromosomes.size(); ++i)
{
Chromosome *chromosome = &(population.chromosomes[i]);
chromosome->fitness_score = 0;
for (int j = 0; j < chromosome->groups.size(); ++j)
{
if(chromosome->groups[j].size() == 0){
//no student in the group
chromosome->fitness_score = INT_MAX;
break;
}
int avg = 0;
int fitness = 0;
for (auto k : chromosome->groups[j])
{
avg += k;
}
avg = avg/chromosome->groups[j].size();
for(auto k: chromosome->groups[j])
{
fitness += square(k - avg);
}
// fitness /= chromosome->groups[j].size();
chromosome->fitness_score += fitness;
}
}
}
int indexAlreadyPresent(int index, vector<int> indices){
for (int i = 0; i < indices.size(); ++i)
{
if(indices[i] == index){
return i;
}
}
return INT_MIN;
}
void initializePopulation(){
cout << "\n=>Initialize popultaion\n";
//initialize with 6 populations
population.chromosomes.resize(POPULATION_SIZE);
for (int i = 0; i < population.chromosomes.size(); ++i)
{
Chromosome *chromosome = &(population.chromosomes[i]);
chromosome->groups.resize(no_of_groups);
vector<int> groupIndices;
for (int k = 0; k < no_of_groups; ++k)
{
int index = rand() % no_of_students;
while (indexAlreadyPresent(index, groupIndices) >= 0)
{
index = rand() % no_of_students;
}
groupIndices.push_back(index);
}
for (int j = 0; j < no_of_students; ++j)
{
int groupNumber = indexAlreadyPresent(j, groupIndices) >=0 ? indexAlreadyPresent(j, groupIndices) : randomGroup();
chromosome->groups[groupNumber].push_back(marks[j]);
chromosome->genes.push_back(groupNumber);
}
}
}
bool sortByFitnessScore(Chromosome A, Chromosome B){
return A.fitness_score < B.fitness_score;
}
void selection(){
cout << "\n=>Selection\n";
sort(population.chromosomes.begin(), population.chromosomes.end(), sortByFitnessScore); //sort in ascending order of fitness score
population.chromosomes.resize(POPULATION_SIZE); //resize to contain 6 populations only, discard others with hiher fitness score i.e. higher diversity
}
int randomCrossOverPoint(){
return 1 + (rand() % (no_of_students - 1));
}
void crossOver(){
cout << "\n=>Crossover\n";
//i, j represents first and second parent respectively
int population_size = population.chromosomes.size();
for (int i = 0, j = 1; j < population_size; i += 2, j += 2)
{
Chromosome parentA = population.chromosomes[i];
Chromosome parentB = population.chromosomes[j];
Chromosome offspringA, offspringB;
offspringA.groups.resize(no_of_groups);
offspringB.groups.resize(no_of_groups);
int crossOverPoint = randomCrossOverPoint();
for (int k = 0; k < no_of_students; ++k)
{
if(k < crossOverPoint){
int groupNumber;
groupNumber = parentB.genes[k]; //for offspring A
offspringA.genes.push_back(groupNumber);
offspringA.groups[groupNumber].push_back(marks[k]);
groupNumber = parentA.genes[k]; //for offspring B
offspringB.genes.push_back(groupNumber);
offspringB.groups[groupNumber].push_back(marks[k]);
}else{
int groupNumber;
groupNumber = parentA.genes[k]; //for offspring A
offspringA.genes.push_back(groupNumber);
offspringA.groups[groupNumber].push_back(marks[k]);
groupNumber = parentB.genes[k]; //for offspring B
offspringB.genes.push_back(groupNumber);
offspringB.groups[groupNumber].push_back(marks[k]);
}
}
population.chromosomes.push_back(offspringA); //push offspring A in population
population.chromosomes.push_back(offspringB); //push offspring B in population
}
}
bool mutationBoolean(){
int mutation_probability = (rand() % 10) / 7;
return mutation_probability > 0 ? true : false;
}
void mutation(){
cout << "\n=>Mutation\n";
for (int k = POPULATION_SIZE; k < population.chromosomes.size(); ++k)
{
Chromosome *chromosome = &(population.chromosomes[k]);
for (int i = 0; i < no_of_students; ++i)
{
if(mutationBoolean){
int swapIndex = rand() % no_of_students;
int indexOfFirstGeneInGroup = 0;
int indexOfSecondGeneInGroup = 0;
int firstGroup = chromosome->genes[i];
int secondGroup = chromosome->genes[swapIndex];
for (int j = 0; j < i; ++j)
{
if(chromosome->genes[j] == firstGroup){
indexOfFirstGeneInGroup++;
}
}
for (int j = 0; j < swapIndex; ++j)
{
if (chromosome->genes[j] == secondGroup)
{
indexOfSecondGeneInGroup++;
}
}
//mutate
chromosome->genes[i] = secondGroup;
chromosome->genes[swapIndex] = firstGroup;
int tempMarks = chromosome->groups[firstGroup][indexOfFirstGeneInGroup];
chromosome->groups[firstGroup][indexOfFirstGeneInGroup] = chromosome->groups[secondGroup][indexOfSecondGeneInGroup];
chromosome->groups[secondGroup][indexOfSecondGeneInGroup] = tempMarks;
}
}
}
}
bool populationConverged(){
int totalFitness = 0;
bool r = false;
for (auto chromosome : population.chromosomes)
{
totalFitness += chromosome.fitness_score;
}
if(totalFitness < lowestTotalFitness){
lowestTotalFitness = totalFitness;
fitness_count = 0;
}else{
fitness_count++;
}
if(fitness_count >= 20){
r = true; //population converges if last 20 generations didn't had any increment in totalFitness value.
}
return r;
}
void displayPopulation(){
cout << "\n------------------------Current populations------------------------\n\n";
cout << "* A higher fitness score signifies higher diversity in distribution and vice-versa.\n";
// cout << "* Parents and offsprings of the genereation are being shown only.\n\n";
cout << "* Fittest 6 (i.e selecions / default POPULATION_SIZE) from previous generation are being shown only.\n";
cout << "* Performance can be made better by increasing the limit of fitness_count variable i.e. controlling convergence. Currently set to 20 iteration if no update found in population, set it to 1000+ for large number of students for better performance.\n\n";
for (int i = 0; i < population.chromosomes.size(); ++i)
{
cout << "chromosome " << i + 1 << " :\t";
for (auto j : population.chromosomes[i].genes)
{
cout << j + 1 << " ";
}
cout <<"\tfitness score = "<<population.chromosomes[i].fitness_score<< endl;
}
}
int main(){
//setting for rand()
srand((unsigned)time(0));
//input required parameters
input();
initializePopulation();
calculateFitness();
displayPopulation();
while (!populationConverged())
{
selection();
displayPopulation();
crossOver();
mutation();
calculateFitness();
// displayPopulation();
}
selection();
displayPopulation();
cout << "\n=> Population converged\n";
cout << "\n\n\n=>=> Solution: Chromosome with the least fitness score in the last population is a better distribution with less diversity of marks.\n\n";
cout << "* As the initial population was totaly a random distribution and crossovers depends on it to a huge extent, so performance also varies with different executions of the program.\n";
return 0;
}