Using structs / genetic algorithm - c++

As practice for myself I'm trying to create a genetic algorithm that will solve equations. So far my program can generate random "genes", fill up individuals with these "genes", and do some basic calculations with the genes (at the moment, simply summing the "genes").
However, I've realised now that I want to implement my fitness function that I would have been better off creating a struct for individual, since I need to keep the genes and the fitness outcome together to have the fittest genes reproduce again.
Anyway, here's my code:
// GA.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <random>
#include <string>
const int population_size = 10;
const int number_of_variables = 7;
struct one_individual
{
std::vector<std::vector<double>>individual;;
double evaluation = 0;
double fit = 0;
};
int main()
{
// Generate random number
std::random_device rd;
std::mt19937 rng(rd()); // random-number engine (Mersenne-Twister in this case)
std::uniform_real_distribution<double> dist(-10.0, 10.0);
// Create vector that holds vectors called individual and fill size it to the amount of individuals I want to have.
std::vector<std::vector<double>>individual;
for (int i = 0; i < population_size; i++)
{
std::vector<double>variables;
for (int j = 0; j < number_of_variables; j++)
{
variables.push_back(dist(rng));
}
individual.push_back(variables);
}
// Display entire population
for (auto &count : individual)
{
for (auto &count2 : count)
{
std::cout << count2 << " ";
}
std::cout << "\n";
}
// Do calculation with population. At the moment I just add up all the genes (sum) and display the sum for each individual.
for (int i = 0; i < population_size; i++)
{
int j = 0;
std::cout << "Organism "<< i;
double sum = individual[i].at(j) + individual[i].at(j + 1) + individual[i].at(j + 2) + individual[i].at(j + 3) + individual[i].at(j + 4) + individual[i].at(j + 5) + individual[i].at(j + 6);
std::cout << " is " << sum << "\n";
}
std::cout << "\n";
return 0;
}
What I think I should be doing is something like this:
for (int i = 0; i < population_size; i++)
{
one_individual individual;
std::vector<double>variables;
for (int j = 0; j < number_of_variables; j++)
{
variables.push_back(dist(rng));
}
one_individual.individual.push_back(variables);
}
The above code is not working. What happens when I try to compile is I get a list of errors, I just pasted it into pastebin since it's a pretty big list: www.pastebin.com/EVJaV0Ex. If I remove everything except the parts needed for the "creating individuals part" the errors that remain are: www.pastebin.com/djw6JmXZ. All errors are on line 41 which is the final line one_individual.individual.push_back(variables);
Edited for clarity, apologies that it was unclear.

Consider the instruction
one_individual.individual.push_back(variables);
where one_individual is a type (struct one_individual).
I suppose you should use the defined variable of type one_individual, so
individual.individual.push_back(variables);

Related

Generate Random 20 Non-repeating numbers in C++

So I have a program where I generate a 8x8 matrix which are rooms. So we have 64 rooms. Now I have to generate 20 random rooms to be dirty. I'm trying to figure out how I can generate 20 non repeating numbers to use as the dirty rooms. This is my code so far:
//generate the 20 random dirty rooms
int col;
int row;
for (int i = 0; i < 20; i++)
{
col = ranNumber();
row = ranNumber();
cout << "\t" << col << " " << row << endl;
if (room[row][col] == 'D')
{
cout << "Duplicate" << endl;
col = ranNumber();
row = ranNumber();
cout << "New number " << row << col << endl;
room[row][col] = 'D';
}
else
//set the room as dirty
room[row][col] = 'D';
}
*ranNumber():
int ranNumber() {
return rand() % 8;
}
Since you're not dealing with a particularly large data set, I'd suggest using std::shuffle. You'll want to initialize your rooms with 20 dirty (the positions don't matter, so do whatever is easiest), then let std::shuffle rearrange the rooms. This avoids you having to write your own loop in case you get poor luck with your random generator, and better expresses your intent.
Sample code:
int main() {
char rooms[8][8];
for(auto i = 0; i < 8; ++i) {
for(auto j = 0; j < 8; ++j) {
rooms[i][j] = (i == 0) ? 'D' : ' ';
}
}
printRooms(rooms);
std::random_device rd{};
std::default_random_engine re{rd()};
auto b = (char *) rooms;
std::shuffle(b, b + (8 * 8), re);
std::cout << "----------------------\n";
printRooms(rooms);
return 0;
}
You can create an array of room numbers (0-63) and use as a picking basket. Whenever a room has been picked, you swap that room out of the selectable range.
Example:
#include <algorithm> // fill_n
#include <iostream>
#include <numeric> // iota
#include <random> // mt19937, random_device, uniform_int_distribution
int main() {
std::mt19937 prng(std::random_device{}());
char room[8][8];
constexpr int room_count = 8 * 8;
std::fill_n(&room[0][0], room_count, '.'); // fill rooms with an initial value.
char numbers[room_count];
std::iota(std::begin(numbers), std::end(numbers), 0); // 0 - 63
for(int i = 1; i <= 20; ++i) {
int last_selectable_room = room_count - i;
std::uniform_int_distribution<int> dist(0, last_selectable_room);
auto& selected = numbers[dist(prng)];
*(&room[0][0] + selected) = 'D';
// swap the selected room number with the last selecable room number
// to make sure that the selected room can't be selected again
std::swap(selected, numbers[last_selectable_room]);
}
}
Demo
This is likely going to be 2.3 - 2.4 times faster than the std::shuffle approach if you use g++ or clang++. Benchmark
If selecting the dirty rooms uniformly at random is truly important, you could build a random permutation of the rooms using Knuth's shuffle (be careful, it is easy to blunder!) and picking e.g. the first 20 ones of the result as dirty.
You could do it using std::shuffle() and a single-dimension array, exploiting the fact that an m x n matrix can be represented as an array containing m*n elements
#include <vector>
#include <random>
#include <algorithm>
class random_room_generator {
public:
random_room_generator(const size_t matrixRows, const size_t matrixColumns) :
m_matrixRows(matrixRows),
m_randomRoomList(),
m_nextRoom(0)
{
// Create a list of all the room numbers.
const size_t totalRooms = matrixRows * matrixColumns;
for (size_t i = 0; i < totalRooms; ++i) {
m_randomRoomList.push_back(i);
}
// Shuffle the list.
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(m_randomRoomList.begin(), m_randomRoomList.end(), g);
}
std::pair<size_t, size_t> next() {
// Get the room number:
const size_t roomNumber = m_randomRoomList[m_nextRoom++];
if (m_nextRoom == m_randomRoomList.size()) {
// Loop back round to the start if we get to the end of the shuffled list.
m_nextRoom = 0;
}
// Convert the room number into a row and column using the modulus/division operators:
return std::pair<size_t, size_t>(roomNumber % m_matrixRows, roomNumber / m_matrixRows);
}
private:
size_t m_matrixRows;
std::vector<size_t> m_randomRoomList;
size_t m_nextRoom;
};
Then, in your function, instead of calling ranNumber(), you can use an instance of random_room_generator to save a list of random rooms and then get 20 rooms from that list:
random_room_generator gen(8, 8);
for (int i = 0; i < 20; i++)
{
std::pair<size_t, size_t> roomCoords = gen.next();
const size_t row = roomCoords.first;
const size_t col = roomCoords.second;
cout << "\t" << col << " " << row << endl;
//set the room as dirty
room[row][col] = 'D';
}
You can find a working example here: https://godbolt.org/z/xKLmjm

How to create a Matrix of random Doubles using Vectors?

I'm having trouble creating a Matrix using Vectors. The rows and columns will all be random doubles and I am trying to fill it in.
I have tried to initialize the size of the vector before hand, I believe it initializes correctly, however, when I try to push onto the rows and columns I get very odd output. Here is my Header File:
#ifndef MATRIX_NORM_HPP
#define MATRIX_NORM_HPP
#include <vector>
class MatrixNorm
{
public:
void initProgram();
void printResults();
double randNumber();
private:
std::vector<std::vector<double>> M;
double mNorm1 = 0.0;
double mNormInf = 0.0;
};
#endif
Here is my CPP File:
#include "matrixNorm.hpp"
#include <iostream>
#include <random>
void initProgram()
{
double ranNum = 0.0;
int size = 0;
std::cout << "Please enter a size of an n by n Matrix: ";
std::cin >> size;
std::vector<std::vector<double>> temp(size, std::vector<double>(size));
for(int i = 0; i < size; ++i)
{
for(int j = 0; j < size; ++j)
{
ranNum = randNumber();
temp[i].push_back(ranNum);
temp[j].push_back(ranNum);
}
}
M = temp;
printResults();
}
void MatrixNorm::printResults()
{
for(auto &&e: M)
{
for(auto && f: e)
{
std::cout << f << " ";
}
std::cout << std::endl;
}
}
double MatrixNorm::randNumber()
{
double ranDouble = 0.0;
std::random_device rd;
std::default_random_engine generator(rd());
std::uniform_real_distribution<double> unif(-1000.0,1000.0);
ranDouble = unif(generator);
return ranDouble;
}
The output I receive when I run the program from main.cpp is:
Please enter a size of an n by n Matrix: 3
0 0 0 792.208 792.208 -361.248 -776.871 742.521 116.732
0 0 0 -361.248 742.521 411.965 411.965 909.313 -50.0048
0 0 0 -776.871 909.313 116.732 -50.0048 79.6189 79.6189
As you can see, it seems to get the column size correctly, but it does not get the row size correctly, and if you look very closely. Some of the numbers are duplicates, I wish I knew how to format it more clearly but if you start at the top left you see 792.208 792.208 then go down a row and you see 411.965 411.965 and last it finishes off at 79.6189 79.6189 in the lower right.
What am I doing wrong? How do I do this correctly? Any help would be appreciated.
Seems to me that the correct way to initialize your matrix is:
(...)
std::vector<std::vector<double>> temp;
for(int i = 0; i < size; ++i)
{
std::vector<double> k;
for(int j = 0; j < size; ++j)
{
ranNum = randNumber();
k.emplace_back(ranNum);
}
temp.emplace_back(k);
}
(...)
Explanation:
with this constructor:
std::vector<std::vector<double>> temp(size, std::vector<double>(size));
you are creating size copies of default vector constructed of size elements (std::vector<double>(size)). In other words, you have a size x size matrix.
So, instead of pushing new values in your code, you should be changing it. In the code I proposed, it is just simpler to populated this matrix when you are creating it.

for looping index of arrays?

I want to output my histogram using the fewest amount of for loops possible
int* histogram(int size, int* arr)
{
int bin[10] = {};
for (int i = 0; i < size; i++)
{
if (arr[i] >= 0 && arr[i] < 10)
{
bin[0]++;
}
else if (arr[i] >= 10 && arr[i] < 20)
{
bin[1]++;
}
return bin;
}
Currently I am outputting the histogram like this:
cout << "0|";
for (int j = 0; j < bin[0]; j++)
cout << "*";
cout << endl;
But this is long and annoying. Is there a way to achieve the same output in fewer
for loops?
I am going to ignore the bugs in your histogram code, as it isn't really relevant to the question of optimising histogram output.
For information on the bug (returning a local variable), check out this Stack Overflow question.
Also, you are missing a curly brace. Always check that your code compiles and runs in its most minimalist form before posting it.
You state that the problem is that the method you use is "long and annoying", but it isn't clear if you are referring to the design of your code or the speed at which it performs.
Performance
The fastest you can possibly read the histogram is with O(n), where n is the number of bins in the histogram. In this sense your code is about as fast as it can get without micro-optimising it.
If you include the printing out of your histogram, then you have O(n*m), where m is the average number of entries per bin.
Writing a histogram is also O(n*k), where k is the number of entries in your array, because you have to figure out which bin each value belongs in.
Design
If the problem you have is that the code is bloated and unwieldy, then use less magic numbers and add more arguments to the function, like this:
#include <iostream>
void histogram(int const size, int const * const arr, unsigned int const number_of_bins, float const bin_min, float const bin_max, int * output)
{
float const binsize = (bin_max - bin_min)/number_of_bins;
for (int i = 0; i < size; i++)
{
for(int j = 0; j < number_of_bins; ++j)
{
if (arr[i] >= bin_min + binsize*j && arr[i] < bin_min + binsize*(j+1))
{
output[j]++;
}
}
}
}
int main(){
int const number_of_bins = 10;
float const bin_min = 0;
float const bin_max = 100;
int const size = 20;
int const array[size] = {5,6,20,40,44,50,110,6,-1,51,55,56,20,50,60,80,81,0,32,3};
int bin[number_of_bins] = {};
histogram(size, array, number_of_bins, bin_min, bin_max, bin);
for(int i = 0; i < number_of_bins; ++i)
{
std::cout << i << "|";
for (int j = 0; j < bin[i]; j++)
{
std::cout << "*";
}
std::cout << std::endl;
}
}
Compiled with:
g++ main.cc -o Output
Output:
0|*****
1|
2|**
3|*
4|**
5|*****
6|*
7|
8|**
9|
(Bonus, your bugs are fixed)
First of all your program is incorrect since, as pointed out, you return a pointer to a local variable form a function. To correct this you should use either std::array<Type, Size> or std::vector<Type>.
Regarding your question if you want short and compact code try this:
#include <string>
#include <algorithm>
#include <iostream>
#include <array>
std::array<int, 10> bin;
// Fill your array here
int i = 0;
std::for_each(bin.begin(), bin.end(), [&i](auto x)
{
std::cout << i++ << "|" << std::string(x, '*') << std::endl;
});
This code takes advantage of fill constructor of std::string which avoids your for cycle. But since you want to iterate through the array you need to do it in one way or the other. Either by an explicit for or by calling another function.
Note: this code is less efficient than a standard for loop but your question is how to avoid these.

Vector inside vector (creating chromosomes)

I'm attempting to build a genetic algorithm that can take a certain amount of variables (say 4), and use these in a way so that you could have 2a + 3b + c*c + d = 16. I realise there are more efficient ways to calculate this, but I want to try and build a genetic algorithm to expand later.
I'm starting by trying to create "organisms" that can compete later. What I've done is this:
#include "stdafx.h"
#include <iostream>
#include <vector>
#include <random>
// Set population size
const int population_size = 10;
const int number_of_variables = 4;
int main()
{
// Generate random number
std::random_device rd;
std::mt19937 rng(rd()); // random-number engine (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(-10, 10);
// Set gene values.
std::vector<int>chromosome;
std::vector<int>variables;
for (int i = 0; i < number_of_variables; ++i)
{
double rand_num = uni(rng);
variables.push_back (rand_num);
std::cout << variables[i] << "\n";
}
return 0;
}
What happens is it will fill up the number_of_variables vector, and output these just because that makes it clear for me that it's actually doing what I intend for it to do. What I want it to do however is to fill up each "chromosome" with one variables vector, so that for example chromosome 0 would have the values {1, 5, -5, 9} etc.
The following code obviously isn't working, but this is what I'd like it to do:
for (int j = 0; j < population_size; ++j)
{
for (int i = 0; i < number_of_variables; ++i)
{
double rand_num = uni(rng);
variables.push_back(rand_num);
}
chromosome.push_back(variables[j]);
std::cout << chromosome[j] << "\n";
}
Meaning it'd fill up the variables randomly, then chromosome1 would take those 4 values that "variables" took, and repeat. What actually happens is that (I think) it only takes the first value from "variables" and copies that into "chromosome" rather than all 4.
If anyone could help it'd be very much appreciated, I realise this might be simply a rookie mistake that is laughably simply in the eyes of someone more experienced with vectors (which would probably be 99% of the people on this website, hah).
Anyway, thanks :)
#include <iostream>
#include <vector>
#include <random>
// Set population size
const int population_size = 10;
const int number_of_variables = 4;
int main()
{
// Generate random number
std::random_device rd;
std::mt19937 rng(rd()); // random-number engine (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(-10, 10);
// Set gene values.
std::vector< std::vector<int>>chromosome;
for( int kp = 0; kp < population_size; kp++ )
{
std::vector<int>variables;
for (int i = 0; i < number_of_variables; ++i)
{
double rand_num = uni(rng);
variables.push_back (rand_num);
}
chromosome.push_back( variables );
}
// display entire population
for( auto c : chromosome )
{
for( auto v : c )
{
std::cout << v << " ";
}
std::cout << "\n";
}
// display 4th member of population
for( auto v : chromosone[ 3 ] )
{
std::cout << v << " ";
}
std::cout << "\n";
return 0;
}
http://ideone.com/2jastJ
You can place a vector inside a vector with the syntax:
std::vector<std::vector<int>>
but you will need to make the outer vector large enough for num_variables.
#include <vector>
#include <cstdlib>
using Individual = std::vector<int>;
using Population = std::vector<Individual>;
// short for std::vector<std::vector<int>>;
const size_t number_of_variables = 8;
int main() {
Population population(10);
for (auto& individual : population) {
individual.resize(number_of_variables);
for (size_t j = 0; j < number_of_variables; ++j) {
individual[j] = j; // replace with random number
}
}
}
Live demo: http://ideone.com/pfufGt

Sorting my 2d array in c++

My homework program has to write random numbers for arrival time and burst time into a file. Then after they are written, it reads the file and sorts the contents.
I figured setting up a 2d array would be the easiest way for me to go about this. But I am unsure on how to implement my sort so that if an arrival time swaps places then burst time of that arrival goes along for the ride.
I feel like I worded that poorly, but a basic example would be:
array[3][10] > array[2][23]
So since second array has an earlier arrival time I need both its arrival 2 and its burst 23 to move before array[3][10], but I need this do that and compare 100 inputs.
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <fstream>
const int max = 100;
using namespace std;
int main()
{
multimap<int [][]> myMap;
int randomBurst[max];
int arrivalTime[max];
int line[max][2];
int first = 0;
for (int i = 0; i < 100; i++)
{
if (i < 100)
{
ofstream write("Schedule.txt", ios::app);
randomBurst[i] = rand() % 1000;
arrivalTime[i] = rand() % 1000;
write << arrivalTime[i] << " " << randomBurst[i] << endl;
}
}
ifstream read("Schedule.txt");
for (int i = 0; i <= max; i++)
{
for (int j = 0; j < 2; j++)
{
read >> line[i][j];
cout << line[i][j] << " " ;
}
cout << endl;
}
cout << endl;
cout << endl;
for (int i = 0; i <= max; i++)
{
for (int j = 0; j < 2; j++)
{
myMap.insert(pair<int[][]>(line[i][j]);
}
cout << endl;
}
system("pause");
return 0;
}
My code sets up my array correctly after it reads the written file content, but I'm kind of lost what I should implement for a sort.
Well coming forward with this, mainly left that comment to be able to find this question faster on my laptop.
Like I said in the comment, if you want a presorted, by key value 2D "array", the quickest manner in which you could do this is with the map container., and if you really need the internal points to be ordered, and you will be using multiple entries within it, lets say entries 2,30 2,12 ... You could either build a map of vectors, or arrays, or use a Multimap. Not too sure of this data structure, as I have never really had a reason to use it as of yet. Referenced here http://www.cplusplus.com/reference/map/multimap/
The above will provide you with the sorting done for you, and the reason why I recommended a vector is the lack of order within it, and not sure if the 'bursts?' are to be ordered as well.
EDIT:
Forgot to mention, that a map will not hold more than one key of any given value, so if you are, again, inputting multiple points a above, then you will. if implementing things as you were before, overwrite things.
EDIT:
So this is more or less the fix I think I have, but you are working around this in a very indirect manner, that is hard to follow honestly.
#include <map>
#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <fstream>
using namespace std;
const int MAX = 100;
int main()
{
multimap<int,int> myMap;
int randomBurst[100];
int arrivalTime[100];
int line[100][2];
int first = 0;
for (int i = 0; i < 100; i++)
{
if (i < 100)
{
ofstream write("Schedule.txt", ios::app);
randomBurst[i] = rand() % 1000;
arrivalTime[i] = rand() % 1000;
write << arrivalTime[i] << " " << randomBurst[i] << endl;
}
}
ifstream read("Schedule.txt");
for (int i = 0; i <= 100; i++)
{
for (int j = 0; j < 2; j++)
{
read >> line[i][j];
cout << line[i][j] << " " ;
}
cout << endl;
}
// cout << endl;
// cout << endl;
for (int i = 0; i < 100; i++)
{
for (int j = 0; j < 2; j++)
{
//Attain the value in the index, and the held value within it.
myMap.insert(pair<int, int> (line[i][j], line[i][j]));
}
cout << endl;
}
// system("pause");
return 0;
This fixes the insertion point, just because you give it an array it does not mean that the program will take that as a pair, as the first index is a point to another array in itself. And so on. I recommend starting off wiht a map object instead, as the multimap makes things a bit annoying, if you are familiar with the vector containers then use that instead within the map to log multiple values.