As part of my training, I implemented a dataset class in C++ that allows me to create synthetic datasets to get more familiar with features that C++ offers such as object oriented programming.
This implementation uses a simple method to create two intertwined spirals as shown in the following image.
The output looks as follows:
x y label
-3.85616 -0.987058 0
1.16 4.6764 0
2.66279 2.13692 1
-0.643551 3.81989 0
-0.252046 -0.888411 0
Please be as hard as possible with this implementation and give me constructive feedback.
I would appreciate advice especially in the following areas:
- Code style (readability, naming conventions, etc...)
- Class design
- Efficiency (how to avoid unnecessary complexity)
- Reinventing the wheel (does the STL offer functionality that I should use?)
main.cpp
#include <iostream>
#include <vector>
#include "data.hpp"
int main() {
unsigned int n_points = 3000;
Data data (n_points);
std::vector<Point> d;
d = data.get();
for (std::vector<Point>::iterator it = d.begin(); it != d.end(); ++it) {
std::cout << it->x << " " << it->y << " " << it->label << std::endl;
}
return 0;
}
data.hpp
#ifndef DATA_H
#define DATA_H
#include <vector>
#include <cmath>
#include "util.hpp"
class Data {
public:
Data (unsigned int);
unsigned int n_samples;
unsigned int n_dims = 2;
unsigned int n_classes = 2;
std::vector<Point> get();
private:
Random random;
std::vector<Point> data;
std::vector<Point> generate_data();
};
Data::Data (unsigned int _n_samples) {
n_samples = _n_samples;
}
std::vector<Point> Data::generate_data() {
std::vector<Point> data(n_samples);
std::vector<Point>::iterator it;
double noise = 1.0;
double spread = 4.0;
for (it = data.begin(); it != data.end(); ++it) {
double r = 3.14 * spread * random.rand();
double r1 = -cos(r) * r + noise * random.rand();
double r2 = sin(r) * r + noise * random.rand();
if (random.rand() < 0.5) {
it->x = r1;
it->y = r2;
it->label = 1;
} else {
it->x = -r1;
it->y = -r2;
it->label = 0;
}
}
return data;
}
std::vector<Point> Data::get() {
std::vector<Point> data(n_samples);
std::vector<Point>::iterator it;
data = generate_data();
return data;
}
#endif /* DATA_H */
util.hpp
#ifndef UTIL_H
#define UTIL_H
#include <cstdlib>
#include <ctime>
struct Point {
double x;
double y;
unsigned int label;
};
class Random {
public:
Random ();
double rand();
};
Random::Random () {
std::srand(static_cast<unsigned int>(std::time(nullptr)));
}
double Random::rand() {
return static_cast<double> (std::rand()) / static_cast<double> (RAND_MAX + 1U);
}
#endif /* UTIL_H */