Skip to content

Commit

Permalink
Add TimeSeriesTester
Browse files Browse the repository at this point in the history
  • Loading branch information
buensons committed Dec 12, 2020
1 parent 51c5df4 commit d509852
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 21 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
bin/*
.vscode/*
predictor
predictor
*.csv
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ INC_DIR = include
EXE = predictor

# Object files:
OBJS = $(OBJ_DIR)/main.o $(OBJ_DIR)/Chromosome.o $(OBJ_DIR)/TimeSeriesPredictor.o $(OBJ_DIR)/FitnessFunctionKernel.o
OBJS = $(OBJ_DIR)/main.o $(OBJ_DIR)/Chromosome.o $(OBJ_DIR)/TimeSeriesPredictor.o $(OBJ_DIR)/FitnessFunctionKernel.o $(OBJ_DIR)/TimeSeriesTester.o

##########################################################

Expand Down
17 changes: 17 additions & 0 deletions include/TimeSeriesTester.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <vector>
#include <cmath>

class TimeSeriesTester {
public:
TimeSeriesTester(std::vector<float> data, std::vector<float> weights, int nodes, int windowSize);

auto test() -> float;

private:
std::vector<float> data;
std::vector<float> dataWeights;
std::vector<float> mapWeights;

int numberOfNodes;
int windowSize;
};
71 changes: 52 additions & 19 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,45 +9,65 @@
#include <algorithm>

#include "include/TimeSeriesPredictor.cuh"
#include "include/TimeSeriesTester.h"

auto readDataToMemory(std::string path) -> std::vector<float>;
auto readDataToMemory(const std::string &path) -> std::vector<float>;
void extractDataFromCsv(const std::string &path, std::vector<float> &data);
void saveWeights(const std::vector<float> &weights);
auto normalizeData(std::vector<float> &data) -> void;
auto usage(char * arg) -> void;

int main(int argc, char ** argv) {
int nodes, populationSize, windowSize;
std::string dataPath;
std::string dataPath, mode, weightsFilePath;
std::vector<float> weights;

if(argc != 5) {
if(argc != 6) {
usage(argv[0]);
return 1;
}

try {
nodes = std::stoi(argv[1]);
populationSize = std::stoi(argv[2]);
mode = std::string(argv[1]);

if(mode != "test" && mode != "train") {
throw std::invalid_argument("Incorrect mode. Available options: test, train\n");
}

nodes = std::stoi(argv[2]);
windowSize = std::stoi(argv[3]);
dataPath = std::string(argv[4]);

if(mode == "train") populationSize = std::stoi(argv[5]);
else weightsFilePath = std::string(argv[5]);

} catch(std::exception const & e) {
usage(argv[0]);
return 1;
throw e;
}

std::cout << "Reading input data from " << dataPath << std::endl;
auto timeSeries = readDataToMemory(dataPath);
normalizeData(timeSeries);

TimeSeriesPredictor predictor(timeSeries, nodes, populationSize, windowSize);
std::vector<float> weights = predictor.train();
if(mode == "test") {
extractDataFromCsv(weightsFilePath, weights);

// TODO: save the weights
// TODO: add predict() method and use test data
TimeSeriesTester tester(timeSeries, weights, nodes, windowSize);
float result = tester.test();
std::cout << "Result on test data: " << result << std::endl;
} else {
TimeSeriesPredictor predictor(timeSeries, nodes, populationSize, windowSize);
weights = predictor.train();
saveWeights(weights);
}

return 0;
}

auto usage(char * arg) -> void {
std::cerr << "Usage: " << arg << " <num_of_nodes> <population_size> <window_size> <path_to_data>" << std::endl;
std::cerr << "Usage: " << arg << " (train | test) <num_of_nodes> <window_size> <path_to_data> "
<< "(<population_size> | <weights_file_path>)" << std::endl;
}

auto normalizeData(std::vector<float> &data) -> void {
Expand All @@ -60,7 +80,7 @@ auto normalizeData(std::vector<float> &data) -> void {
}
}

auto extractDataFromCsv(std::string path, std::vector<float> &dataVector) {
void extractDataFromCsv(const std::string &path, std::vector<float> &data) {
std::ifstream infile(path);
std::string line;

Expand All @@ -70,32 +90,45 @@ auto extractDataFromCsv(std::string path, std::vector<float> &dataVector) {
while(iss.good()){
std::string substr;
getline(iss, substr, ',');
dataVector.push_back(std::stof(substr));
data.push_back(std::stof(substr));
}
}
}

auto readDataToMemory(std::string path) -> std::vector<float> {
std::vector<float> dataVector;
auto readDataToMemory(const std::string &path) -> std::vector<float> {
std::vector<float> data;

size_t pos = path.rfind('.');

if (pos != std::string::npos) {
std::string ext = path.substr(pos+1);

if (ext == "csv") {
extractDataFromCsv(path, dataVector);
return dataVector;
extractDataFromCsv(path, data);
return data;
}
}

for(auto& p: std::filesystem::directory_iterator(path)) {
const auto extension = p.path().extension();

if(extension == ".csv") {
extractDataFromCsv(p.path().string(), dataVector);
extractDataFromCsv(p.path().string(), data);
}
}

return dataVector;
return data;
}

void saveWeights(const std::vector<float> &weights) {
std::ofstream file;
file.open ("./weights.csv");

for(auto weight: weights) {
file << weight << std::endl;
}

file.close();

std::cout << "Weights saved to weights.csv file" << std::endl;
}
51 changes: 51 additions & 0 deletions src/TimeSeriesTester.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include "../include/TimeSeriesTester.h"

TimeSeriesTester::TimeSeriesTester(std::vector<float> data, std::vector<float> weights, int nodes, int windowSize)
: dataWeights(data.begin(), data.begin() + nodes * windowSize),
mapWeights(data.begin() + nodes * windowSize, data.end())
{
this->data = data;
this->numberOfNodes = nodes;
this->windowSize = windowSize;
}

auto TimeSeriesTester::test() -> float {
float cumulativeError = 0.0;
int i = 0;

std::vector<float> mapInput(this->numberOfNodes, 0.0);

while(i < data.size() - windowSize * numberOfNodes) {

// data aggregation
for(int j = 0; j < windowSize * numberOfNodes; ++j) {
mapInput[j % numberOfNodes] += dataWeights[j] * data[i + j];
}

// squashing function for map input
for(int j = 0; j < numberOfNodes; ++j) {
mapInput[j] = 1.0 / (1.0 + std::exp(-5 * mapInput[j]));
}

// one step of cognitive map computation for each node
for(int j = 0; j < numberOfNodes; ++j) {

float x = 0.0f;
for(int k = 0; k < numberOfNodes; ++k) {
x += mapWeights[j * numberOfNodes + k] * mapInput[k];
}

float y = 1.0 / (1.0 + std::exp(-5 * x));
float prediction_error = std::abs(y - data[windowSize * numberOfNodes + i + j]);

// TODO: experiment with percentage error
// TODO: experiment with max percentage error
cumulativeError += prediction_error;
}
i += numberOfNodes;
}

float epsilon = cumulativeError / ((numberOfNodes * data.size()) - (numberOfNodes * windowSize));

return 1.0 / (1.0 + epsilon);
}

0 comments on commit d509852

Please sign in to comment.