Last active
July 12, 2018 15:11
-
-
Save EmmanuelMess/4a9d0c467ef783cda85bbedf01fef355 to your computer and use it in GitHub Desktop.
Perceptron learning algorithm (the worst one) implementation with heuristic
This file contains 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 <iostream> | |
#include <vector> | |
#include <random> | |
enum Halfspace {N, P}; | |
typedef double T; | |
class VectorWrongSizeException : public std::exception { | |
const char* what() const noexcept override { | |
return "Different vector sizes!"; | |
} | |
}; | |
class MissingDatapointsException : public std::exception { | |
const char* what() const noexcept override { | |
return "You need at least one datapoint for the negative halfspace and one for the positive halfspace!"; | |
} | |
}; | |
class Vector : public std::vector<T> { | |
public: | |
explicit Vector(size_t size) : std::vector<T>(size) { } | |
explicit Vector(const vector<T>& v) : std::vector<T>(v) { } | |
void operator+=(const Vector& o) { | |
if(size() != o.size()) { | |
throw VectorWrongSizeException(); | |
} | |
for (size_t i = 0; i < size(); i++) { | |
(*this)[i] += o[i]; | |
} | |
} | |
void operator-=(const Vector& o) { | |
if(size() != o.size()) { | |
throw VectorWrongSizeException(); | |
} | |
for (size_t i = 0; i < size(); i++) { | |
(*this)[i] -= o[i]; | |
} | |
} | |
Vector operator/(int o) const { | |
Vector newV(size()); | |
for (size_t i = 0; i < size(); i++) { | |
newV[i] = (*this)[i] / o; | |
} | |
return newV; | |
} | |
}; | |
class Perceptron { | |
Vector w; | |
public: | |
explicit Perceptron(std::vector<std::pair<Vector, Halfspace>>& inputs) : w(inputs[0].first.size()) { | |
Vector p(w.size()); int lengthP = 0; | |
Vector n(w.size()); int lengthN = 0; | |
for (auto &input : inputs) { | |
if(input.second == Halfspace::N) { | |
p += input.first; | |
lengthN++; | |
} else { | |
n += input.first; | |
lengthP++; | |
} | |
} | |
if(lengthP == 0 || lengthN == 0) { | |
throw MissingDatapointsException(); | |
} | |
w = (p/lengthP); | |
w -= (n/lengthN); | |
} | |
T compute(const Vector &x) { | |
if(x.size() != w.size()) { | |
throw VectorWrongSizeException(); | |
} | |
T sum = 0; | |
for (int i = 0; i < x.size(); ++i) { | |
sum += w[i] * x[i]; | |
} | |
return sum; | |
} | |
void operator+=(Vector& o) { | |
w += o; | |
} | |
void operator-=(Vector& o) { | |
w -= o; | |
} | |
friend std::ostream &operator<<(std::ostream& strm, const Perceptron& obj); | |
}; | |
std::ostream &operator<<(std::ostream& strm, const Perceptron& obj) { | |
strm << "[" << obj.w.size() << "]{"; | |
for (int i = 0; i < obj.w.size(); i++) { | |
if(i == obj.w.size()-1) { | |
strm << "(θ) "; | |
} | |
strm << obj.w[i]; | |
if(i < obj.w.size()-1) { | |
strm << ", "; | |
} | |
} | |
strm << "}"; | |
} | |
void andDatapoints(std::vector<std::pair<Vector, Halfspace>>& inputs) { | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({0, 0, 1}), Halfspace::N)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({0, 1, 1}), Halfspace::N)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({1, 0, 1}), Halfspace::N)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({1, 1, 1}), Halfspace::P)); | |
} | |
void orDatapoints(std::vector<std::pair<Vector, Halfspace>>& inputs) { | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({0, 0, 1}), Halfspace::N)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({0, 1, 1}), Halfspace::P)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({1, 0, 1}), Halfspace::P)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({1, 1, 1}), Halfspace::P)); | |
} | |
void firstParameterFunctionDatapoints(std::vector<std::pair<Vector, Halfspace>>& inputs) { | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({0, 0, 1}), Halfspace::N)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({0, 1, 1}), Halfspace::N)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({1, 0, 1}), Halfspace::P)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({1, 1, 1}), Halfspace::P)); | |
} | |
/** | |
* Impossible | |
*/ | |
void xorDatapoints(std::vector<std::pair<Vector, Halfspace>>& inputs) { | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({0, 0, 1}), Halfspace::N)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({0, 1, 1}), Halfspace::P)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({1, 0, 1}), Halfspace::P)); | |
inputs.push_back(std::pair<Vector, Halfspace>(Vector({1, 1, 1}), Halfspace::N)); | |
} | |
int main() { | |
using std::cout; | |
using std::cin; | |
using std::endl; | |
std::vector<std::pair<Vector, Halfspace>> inputs; | |
andDatapoints(inputs);//Change datapoints for different trainings | |
Perceptron p(inputs); | |
cout << p << endl; | |
int total = 0; | |
restart: | |
for(int i = 0; i < inputs.size(); i++, total++) { | |
if(inputs[i].second == Halfspace::N) { | |
if (p.compute(inputs[i].first) >= 0) { | |
p -= inputs[i].first; | |
goto restart; | |
} | |
} else { | |
if (p.compute(inputs[i].first) <= 0) { | |
p += inputs[i].first; | |
goto restart; | |
} | |
} | |
} | |
cout << p << endl; | |
cout << "Tries: " << total << endl; | |
for (const auto &x : inputs) { | |
cout << "(" << x.first[0] << ", " << x.first[1] << ") = " << p.compute(x.first) << endl; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment