Brain.cpp
#include
#include // std::chrono::system_clock
#include
#include
#include "net.h"
#include "verylong.h"
#include "string.h"
int main()
{
std::vector result;
//std::string regex = "[\\s,]+";
//std::string regex = "([A-Za-z])*";
//std::string regex = "([\\d]+)";
//std::string regex = "([\\d]+).*([\\d]+)";
// std::string regex = "([\\d]+).+([\\d]+)";
//std::string regex = "\\b([\\d])([^ ]*)";
std::string regex = "([A-Z]+)([\\d]+)";
std::regex reg(regex);
std::cout << "RS=" << reg.mark_count() << std::endl;
//std::string ss = "The1White2Rabbit,333is4very,late.";
//std::string ss = "5yz0ab1cde2fgh";
//std::string ss = "MAY14";
std::string ss = "aaaMAY14bbbJUNE4";
result = string_find(ss, regex);
for (int i = 0; i < result.size(); i++)
{
std::cout << "[" << i << "]=" << result[i] << "#" << std::endl;
}
// std::string s("This is a catfish");
// std::string regex("(cat)");
// std::string r("(dog)");
ss = "This cat is a catfish";
regex = "(cat)";
std::string result2;
result2 = string_replace(ss, regex, "dog", std::regex_constants::format_first_only);
std::cout << result2 << std::endl;
result2 = string_replace(ss, regex, "ha ha $$1 boo");
std::cout << result2 << std::endl;
result2 = string_replace(ss, regex, "ha ha $$1 boo", false);
std::cout << result2 << std::endl;
ss = "there is a subsequence in the string\n";
regex = "(sub)";
result2 = string_replace(ss, regex, "xyz");
std::cout << result2 << std::endl;
ss = "April 15, 2003";
regex = "(\\w+) (\\d+), (\\d+)";
result2 = string_replace(ss, regex, "$011,$3");
std::cout << result2 << std::endl;
ss = " 14MAY 15JUNE ";
std::cout << "[" << ss << "]" << std::endl;
//regex = "([\\d]+)([A+Z]+)";
regex = "(\\d+)([A-Z]+)";
result2 = string_replace(ss, regex, "$1 $2");
std::cout << "[" << result2 << "]" << std::endl;
result2 = string_replace(ss, regex, "$1 $2", std::regex_constants::format_no_copy);
std::cout << "[" << result2 << "]" << std::endl;
result2 = string_replace(ss, regex, "$1 $2", false);
std::cout << "[" << result2 << "]" << std::endl;
/*
std::string s3("there is a subsequence in the string\n");
std::regex e("\\b(sub)([^ ]*)"); // matches words beginning by "sub"
// using string/c-string (3) version:
std::cout << std::regex_replace(s3, e, "sub-$2");
// using range/c-string (6) version:
std::string result2;
std::regex_replace(std::back_inserter(result2), s3.begin(), s3.end(), e, "$2");
std::cout << result2;
// with flags:
std::cout << std::regex_replace(s3, e, "$1 and $2", std::regex_constants::format_no_copy);
std::cout << std::endl;
*/
std::cout << "HEAD" << std::endl;
ss = "0 HEAD";
regex = "([\\d]+)[\\s]+([A-Z]*)$";
//regex = "([\\d]+)([A-Z]*)";
// regex = "[\\d]+[A-Z]*";
result.clear();
result = string_tokenize(ss, regex);
for (int i = 0; i < result.size(); i++)
{
std::cout << "[" << i << "]=" << result[i] << "#" << std::endl;
}
/*
show_matches("abcdef", "abc|def");
show_matches("abc", "ab|abc"); // left Alernative matched first
show_matches("abc", "((a)|(ab))((c)|(bc))");
*/
#ifdef _MSC_VER
std::string s1;
std::getline(std::cin, s1);
#endif
//return 0;
/*
Verylong v1("12345678901234567890123456789");
v1 = 2;
std::cout << "V1=" << v1 << std::endl;
Verylong v2(1);
v1 += v2;
std::cout << "V1=" << v1 << std::endl;
v1 ^= 80;
//v1 ^= 5;
std::cout << "V1=" << v1 << std::endl;
Verylong v3(0);
v1 = 12;
v2 = 2;
v3 = v1 ^ v2;
std::cout << "V3=" << v3 << std::endl;
Verylong v4(0);
v4 = v1;
std::cout << "V4=" << v4 << std::endl;
//return 0;
*/
std::vector myvector;
// set some values (from 1 to 10)
for (int i = 1; i <= 10; i++) myvector.push_back(i);
// erase the 6th element
myvector.erase(myvector.begin() + 5);
// erase the first 3 elements:
myvector.erase(myvector.begin(), myvector.begin() + 3);
std::cout << "myvector contains:";
for (unsigned i = 0; i myDQNTopology;
myDQNTopology.push_back(6); // 6 neurons. (in layer 0).
std::cout << myDQNTopology.size() << std::endl << std::endl; // myTopology == {3, 4, 2 ,1}
Net myDQN(myDQNTopology);
myDQN.setGoalAmount(100);
const std::vector< std::vector > connections = {
//{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 4, 0 }, // from Layer 0, Neuron 0 to Layer 0, Neuron 4 give a value of zero.
{ 0, 1, 0, 1, 0 },
{ 0, 1, 0, 3, 0 },
{ 0, 1, 0, 5, 100 },
//{ 0, 2, 0, 2, 0 },
{ 0, 2, 0, 3, 0 },
//{ 0, 3, 0, 3, 0 },
{ 0, 3, 0, 1, 0 },
{ 0, 3, 0, 2, 0 },
{ 0, 3, 0, 4, 0 },
//{ 0, 4, 0, 4, 0 },
{ 0, 4, 0, 0, 0 },
{ 0, 4, 0, 3, 0 },
{ 0, 4, 0, 5, 100 },
{ 0, 5, 0, 5, 100 },
{ 0, 5, 0, 1, 0 },
{ 0, 5, 0, 4, 0 }
};
/*
const std::vector< std::vector > connections = {
{ 0, 0, 0, 0, 0 },
{ 0, 0, 0, 1, 0 },
{ 0, 0, 0, 3, 0 },
{ 0, 1, 0, 1, 0 },
{ 0, 1, 0, 0, 0 },
{ 0, 1, 0, 2, 100 },
{ 0, 2, 0, 2, 100 },
{ 0, 2, 0, 1, 0 },
{ 0, 2, 0, 5, 0 },
{ 0, 3, 0, 3, 0 },
{ 0, 3, 0, 0, 0 },
{ 0, 2, 0, 4, 0 },
{ 0, 4, 0, 4, 0 },
{ 0, 4, 0, 1, 0 },
{ 0, 4, 0, 3, 0 },
{ 0, 4, 0, 5, 0 },
{ 0, 5, 0, 5, 0 },
{ 0, 5, 0, 2, 100 },
{ 0, 5, 0, 4, 0 }
};
*/
myDQN.connect(connections);
/*
unsigned int connection_idx = 0;
myDQN.connect(0, 0, 0, 0, 0, connection_idx++);
myDQN.connect(0, 0, 0, 4, 0, connection_idx++);
myDQN.connect(0, 1, 0, 1, 0, connection_idx++);
myDQN.connect(0, 1, 0, 3, 0, connection_idx++);
myDQN.connect(0, 1, 0, 5, 100, connection_idx++);
myDQN.connect(0, 2, 0, 2, 0, connection_idx++);
myDQN.connect(0, 2, 0, 3, 0, connection_idx++);
myDQN.connect(0, 3, 0, 3, 0, connection_idx++);
myDQN.connect(0, 3, 0, 1, 0, connection_idx++);
myDQN.connect(0, 3, 0, 2, 0, connection_idx++);
myDQN.connect(0, 3, 0, 4, 0, connection_idx++);
myDQN.connect(0, 4, 0, 4, 0, connection_idx++);
myDQN.connect(0, 4, 0, 0, 0, connection_idx++);
myDQN.connect(0, 4, 0, 3, 0, connection_idx++);
myDQN.connect(0, 4, 0, 5, 100, connection_idx++);
myDQN.connect(0, 5, 0, 5, 100, connection_idx++);
myDQN.connect(0, 5, 0, 1, 0, connection_idx++);
myDQN.connect(0, 5, 0, 4, 0, connection_idx++);
*/
/*
myDQN.connect(0, 0, 0, 0, 0, connection_idx++);
myDQN.connect(0, 0, 0, 1, 0, connection_idx++);
myDQN.connect(0, 0, 0, 3, 0, connection_idx++);
myDQN.connect(0, 1, 0, 1, 0, connection_idx++);
myDQN.connect(0, 1, 0, 0, 0, connection_idx++);
myDQN.connect(0, 1, 0, 2, 100, connection_idx++);
myDQN.connect(0, 2, 0, 2, 100, connection_idx++);
myDQN.connect(0, 2, 0, 1, 0, connection_idx++);
myDQN.connect(0, 2, 0, 5, 0, connection_idx++);
myDQN.connect(0, 3, 0, 3, 0, connection_idx++);
myDQN.connect(0, 3, 0, 0, 0, connection_idx++);
myDQN.connect(0, 3, 0, 4, 0, connection_idx++);
myDQN.connect(0, 4, 0, 4, 0, connection_idx++);
myDQN.connect(0, 4, 0, 1, 0, connection_idx++);
myDQN.connect(0, 4, 0, 3, 0, connection_idx++);
myDQN.connect(0, 4, 0, 5, 0, connection_idx++);
myDQN.connect(0, 5, 0, 5, 0, connection_idx++);
myDQN.connect(0, 5, 0, 4, 0, connection_idx++);
myDQN.connect(0, 5, 0, 2, 100, connection_idx++);
*/
myDQN.printOutput();
for (unsigned int i = 0; i<1000; ++i)
myDQN.DQN();
myDQN.printOutput();
myDQN.printResult();
myDQN.showPolicy();
#ifdef _MSC_VER
std::string s2;
std::getline(std::cin, s2);
#endif
return 0;
std::cout << "****************BACKPROP***********************" << std::endl;
srand((unsigned int)time(NULL));
std::vector myTopology;
myTopology.push_back(2);
//myTopology.push_back(3); 1 for bias.
myTopology.push_back(4);
//myTopology.push_back(8);
//myTopology.push_back(2);
myTopology.push_back(1);
std::cout << myTopology.size() << std::endl << std::endl; // myTopology == {3, 4, 2 ,1}
//Neural::Net myNet(myTopology);
Net myNet(myTopology);
std::cout << "****************SET VALS***********************" << std::endl;
myNet.connectForward();
//myNet.setTest();
std::cout << "****************FORWARD***********************" << std::endl;
/*
for (unsigned int i = 0; i<50; ++i)
{
myNet.feedForward({ 1, 1 });
myNet.backPropagate({ 0 });
}
for (unsigned int i = 0; i<50; ++i)
{
myNet.feedForward({ 0, 0 });
myNet.backPropagate({ 1 });
}
*/
for (unsigned int i = 0; i<50000; ++i)
//for (unsigned int i = 0; i<100000; ++i)
//for (unsigned int i = 0; i<500000; ++i)
{
myNet.feedForward({ 0, 0 });
myNet.backPropagate({ 0 });
myNet.feedForward({ 1, 0 });
myNet.backPropagate({ 1 });
myNet.feedForward({ 0, 1 });
myNet.backPropagate({ 1 });
myNet.feedForward({ 1, 1 });
myNet.backPropagate({ 0 });
}
/*
std::cout << "Feeding 0,0" << std::endl;
myNet.feedForward({ 0, 0 });
myNet.printOutput();
std::cout << "Feeding 1,1" << std::endl;
myNet.feedForward({ 1, 1 });
myNet.printOutput();
*/
std::cout << "****************BACK**************************" << std::endl;
//myNet.backPropagate({0});
std::cout << "Feeding 0,0" << std::endl;
myNet.feedForward({ 0, 0 });
//myNet.printOutput();
myNet.printResult();
//myNet.backPropagate({1});
std::cout << "Feeding 1,0" << std::endl;
myNet.feedForward({ 1, 0 });
//myNet.printOutput();
myNet.printResult();
//myNet.backPropagate({1});
std::cout << "Feeding 1,1" << std::endl;
myNet.feedForward({ 1, 1 });
//myNet.printOutput();
myNet.printResult();
//myNet.backPropagate({1});
std::cout << "Feeding 0,1" << std::endl;
myNet.feedForward({ 0, 1 });
//myNet.printOutput();
myNet.printResult();
#ifdef _MSC_VER
std::string s;
std::getline(std::cin, s);
#endif
return 0;
}
activation.cpp
#include
#include "activation.h"
Activation::Activation()
{
activation_type = ACTIVATION_SIGMOID;
}
Activation::Activation(Activation_Types _activation_type)
{
activation_type = _activation_type;
}
Activation::~Activation()
{
}
double Activation::activate(const double& value, const bool derivative)
{
switch (activation_type)
{
case (ACTIVATION_ABS) :
return (abs(value, derivative));
break;
case (ACTIVATION_ARCTAN) :
return (arctan(value, derivative));
break;
case (ACTIVATION_BOUNDEDRELU) :
return (boundedRelu(value, derivative));
break;
case (ACTIVATION_ELU) :
return (elu(value, derivative));
break;
case (ACTIVATION_GAUSSIAN) :
return (gaussian(value, derivative));
break;
case (ACTIVATION_LINEAR) :
return (linear(value, derivative));
break;
case (ACTIVATION_LOG) :
return (log(value, derivative));
break;
case (ACTIVATION_RELU) :
return (relu(value, derivative));
break;
case (ACTIVATION_SCALED_TANH) :
return (tanh(value, derivative));
break;
case (ACTIVATION_SIGMOID) :
return (sigmoid(value, derivative));
break;
case (ACTIVATION_SOFTRELU) :
return (softRelu(value, derivative));
break;
case (ACTIVATION_SQRT) :
return (sqrt(value, derivative));
break;
case (ACTIVATION_SQUARE) :
return (square(value, derivative));
break;
case (ACTIVATION_SQUASH) :
return (squash(value, derivative));
break;
case (ACTIVATION_STEP) :
return (step(value, derivative));
break;
case (ACTIVATION_TANH) :
return (tanh(value, derivative));
break;
default:
return (sigmoid(value, derivative));
break;
}
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = abs(x)
double Activation::abs(const double& value, const bool derivative)
{
if (derivative)
return value < 0 ? -1 : 1;
else
return std::abs(value);
}
// Returns a value between -1.0 and +1.0.
double Activation::arctan(const double& value, const bool derivative)
{
if (derivative)
return (std::cos(value) * std::cos(value));
else
return std::atan(value);
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = min(a, max(0, x))
double Activation::boundedRelu(const double& value, const bool derivative)
{
if (derivative)
return 0; // TODO
else
return 0; // TODO
}
// Returns a value between -1.0 and +1.0.
//
// f(x) =
double Activation::elu(const double& value, const bool derivative)
{
if (derivative)
{
double output = elu(value);
return output > 0 ? 1.0 : output + 1;
}
else
return value > 0 ? value : std::exp(value) - 1;
}
// Returns a value between -1.0 and +1.0.
//
// f(x) =
double Activation::gaussian(const double& value, const bool derivative)
{
if (derivative)
return -2 * value * std::exp(-value * -value);
else
return std::exp(-value * -value);
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = a*x + b
double Activation::linear(const double& value, const bool derivative)
{
if (derivative)
return 1;
else
return value;
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = 1 / (1 + e^-x)
double Activation::log(const double& value, const bool derivative)
{
if (derivative)
return 0; // TODO
else
return 1.0 / (1.0 + std::exp(-value));
/*
if (value < -45.0)
return 0.0;
else
if (value > 45.0)
return 1.0;
else
return 1.0 / (1.0 + std::exp(-value));
*/
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = max(0, x)
double Activation::relu(const double& value, const bool derivative)
{
if (derivative)
return value > 0 ? 1.0 : 0.0;
else
return value > 0 ? value : 0;
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = 1.7159 * tanh(0.66667 * x)
double Activation::scaledTanh(const double& value, const bool derivative)
{
if (derivative) // TODO...
{
double tanh_value = std::tanh(value);
return 0.66667f * (1.7159f - 1 / 1.7159f * tanh_value * tanh_value);
}
else
return 1.7159 * std::tanh(0.66667 * value);
}
// Returns a value between 0.0 and 1.0.
double Activation::sigmoid(const double& value, const bool derivative)
{
if (derivative)
return sigmoid(value) * (1.0 - sigmoid(value));
else
return 1.0 / double((1.0 + exp(-value)));
}
/*
// Returns a value between 0.0 and 1.0.
double Activation::sigmoid(const double& value)
{
return 1.0 / double((1.0 + exp(-value)));
}
double Activation::sigmoid_derivative(const double& value)
{
return sigmoid(value) * (1.0 - sigmoid(value));
}
*/
double Activation::sigmoid_limit(double value, double positive_limit, double negative_limit)
{
if (value < negative_limit)
return 0.0;
else
if (value > positive_limit)
return 1.0;
else
return 1.0 / (1.0 + exp(-value));
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = log(1 + e^x)
double Activation::softRelu(const double& value, const bool derivative)
{
if (derivative)
return 0; // TODO
else
return 0; // TODO
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = sqrt(x)
double Activation::sqrt(const double& value, const bool derivative)
{
if (derivative)
return 0; // TODO
else
return std::sqrt(value); // TODO
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = x^2
double Activation::square(const double& value, const bool derivative)
{
if (derivative)
return 0; // TODO
else
return value * value; // TODO
}
// Returns a value between -1.0 and +1.0.
//
// f(x) =
double Activation::squash(const double& value, const bool derivative)
{
if (derivative)
{
if (value > 0)
return (value) / (1 + value);
else
return (value) / (1 - value);
}
else
return (value) / (1 + std::abs(value));
}
// Returns a value between -1.0 and +1.0.
//
// f(x) =
double Activation::step(const double& value, const bool derivative)
{
if (derivative)
{
if (value > 0)
return 0;
else
return value;
}
else
{
if (value > 0)
return 1;
else
return 0;
}
}
// Returns a value between -1.0 and +1.0.
//
// f(x) = a*tanh(b*x)
double Activation::tanh(const double& value, const bool derivative)
{
if (derivative)
{
double tanh_value = std::tanh(value);
return (1.0 - tanh_value * tanh_value);
//return (1.0 - std::tanh(value)) * (1.0 + std::tanh(value));
}
else
return std::tanh(value);
/*
if (value < -45.0)
return -1.0;
else
if (value > 45.0)
return 1.0;
else
return std::tanh(value);
*/
}
// Returns a value between -1.0 and +1.0.
double Activation::tanh_limit(double& value, double positive_limit, double negative_limit)
{
if (value < negative_limit)
return -1.0;
else
if (value > positive_limit)
return 1.0;
else
return tanh(value);
}
Activation_Types Activation::getActivationType()
{
return activation_type;
}
void Activation::setActivationType(Activation_Types _activation_type)
{
activation_type = _activation_type;
}
/*
public double SoftMax(double x, string layer)
{
// Determine max
double max = double.MinValue;
if (layer == "ih")
max = (ihSum0 > ihSum1) ? ihSum0 : ihSum1;
else
if (layer == "ho")
max = (hoSum0 > hoSum1) ? hoSum0 : hoSum1;
// Compute scale
double scale = 0.0;
if (layer == "ih")
scale = Math.Exp(ihSum0 - max) + Math.Exp(ihSum1 - max);
else
if (layer == "ho")
scale = Math.Exp(hoSum0 - max ) + Math.Exp(hoSum1 - max);
return Math.Exp(x - max) / scale;
}
*/
activation.h
#ifndef __SHAREWIZ_ACTIVATION_H__
#define __SHAREWIZ_ACTIVATION_H__
#include
// Built-in activation functions.
enum Activation_Types
{
ACTIVATION_ABS, // Absolute value.
ACTIVATION_ARCTAN, // Arctan.
ACTIVATION_BOUNDEDRELU, // Bounded rectified linear.
ACTIVATION_ELU, //
ACTIVATION_GAUSSIAN, // Gaussian.
ACTIVATION_LINEAR, // Linear.
ACTIVATION_LOG, // Logistic.
ACTIVATION_RELU, // Rectified linear.
ACTIVATION_SCALED_TANH, // Scaled Tanh 1.7159 * tanh(0.66667 * x ).
ACTIVATION_SIGMOID, // Sigmoid.
ACTIVATION_SOFTRELU, // Soft rectified linear.
ACTIVATION_SQRT, // Square Root.
ACTIVATION_SQUARE, // Square.
ACTIVATION_SQUASH, // Squash.
ACTIVATION_STEP, // Step.
ACTIVATION_TANH // Hyperbolic tangent.
};
class Activation;
typedef std::shared_ptr pActivationX;
//typedef std::vector pActivation;
class Activation
{
private:
//enum {SIGMOID, TANH, RELU, LINEAR} types;
//types type;
Activation_Types activation_type;
public:
Activation();
Activation(Activation_Types _activation_type);
~Activation();
double activate(const double& value, const bool derivative=false);
double abs(const double& value, const bool derivative=false);
double arctan(const double& value, const bool derivative=false);
double boundedRelu(const double& value, const bool derivative=false);
double elu(const double& value, const bool derivative = false);
double gaussian(const double& value, const bool derivative = false);
double linear(const double& value, const bool derivative=false);
double log(const double& value, const bool derivative=false);
double relu(const double& value, const bool derivative = false);
double scaledTanh(const double& value, const bool derivative = false);
double sigmoid(const double& value, const bool derivative=false);
double sigmoid_limit(double value, double positive_limit=45.0, double negative_limit=-45.0);
double softRelu(const double& value, const bool derivative=false);
double sqrt(const double& value, const bool derivative = false);
double square(const double& value, const bool derivative=false);
double squash(const double& value, const bool derivative = false);
double step(const double& value, const bool derivative = false);
double tanh(const double& value, const bool derivative = false);
double tanh_limit(double& value, double positive_limit=10.0, double negative_limit=-10.0);
Activation_Types getActivationType();
void setActivationType(Activation_Types _activation_type);
//double sigmoid(const double& value);
//double sigmoid_derivative(const double& value);
//double tanh_derivative(const double& value);
};
/*
// Built-in activation functions
export class Activations {
public static TANH: ActivationFunction = {
output: x = > (Math).tanh(x),
der: x = > {
let output = Activations.TANH.output(x);
return 1 - output * output;
}
};
public static RELU: ActivationFunction = {
output: x = > Math.max(0, x),
der: x = > x <= 0 ? 0 : 1
};
public static SIGMOID: ActivationFunction = {
output: x = > 1 / (1 + Math.exp(-x)),
der: x = > {
let output = Activations.SIGMOID.output(x);
return output * (1 - output);
}
};
public static LINEAR: ActivationFunction = {
output: x = > x,
der: x = > 1
};
}
/* Build-in regularization functions.
export class RegularizationFunction {
public static L1: RegularizationFunction = {
output: w = > Math.abs(w),
der: w = > w < 0 ? -1 : 1
};
public static L2: RegularizationFunction = {
output: w = > 0.5 * w * w,
der: w = > w
};
}
*/
#endif
connection.cpp
#include
#include
#include "neuron.h"
#include "connection.h"
Connection::Connection()
{
#ifdef DEBUG
std::cout << "Connection::Connection1" << std::endl;
#endif
index = -1;
deltaWeight = 0;
weight = 0;
momentum = 0.4;
Q = 0;
R = -1;
randomizeWeight();
}
Connection::Connection(const pNeuronX& from, const pNeuronX& to)
{
#ifdef DEBUG
std::cout << "Connection::Connection2" << std::endl;
#endif
index = -1;
deltaWeight = 0;
weight = 0;
momentum = 0.4;
Q = 0;
R = -1;
this->from = from;
this->to = to;
randomizeWeight();
}
double Connection::getError(void)
{
#ifdef DEBUG
std::cout << "Connection::getError" << std::endl;
#endif
return error;
}
void Connection::setError(const double& e)
{
#ifdef DEBUG
std::cout << "Connection::setError" << std::endl;
#endif
error = e;
}
int Connection::getIndex(void)
{
#ifdef DEBUG
std::cout << "Connection::getIndex" << std::endl;
#endif
return index;
}
void Connection::setIndex(const int& index)
{
#ifdef DEBUG
std::cout << "Connection::setIndex" << std::endl;
#endif
this->index = index;
}
double Connection::getWeight(void)
{
#ifdef DEBUG
std::cout << "Connection::getWeight" << std::endl;
#endif
return weight;
}
void Connection::setWeight(const double& w)
{
#ifdef DEBUG
std::cout << "Connection::setWeight" << std::endl;
#endif
//deltaWeight = weight - w;
weight = w;
}
double Connection::getDeltaWeight(void)
{
#ifdef DEBUG
std::cout << "Connection::getDeltaWeight" << std::endl;
#endif
return deltaWeight;
}
void Connection::setDeltaWeight(const double& dw)
{
#ifdef DEBUG
std::cout << "Connection::setDeltaWeight" << std::endl;
#endif
deltaWeight = dw;
}
// Controls how much the weights are changed during a weight update by factoring in previous weight updates.
// It acts as a smoothing parameter that reduces oscillation and helps attain convergence.
// This must be a real value between 0.0 and 1.0, a typical value for momentum is 0.9.
double Connection::getMomentum(void)
{
#ifdef DEBUG
std::cout << "Connection::getMomentum" << std::endl;
#endif
return momentum;
}
void Connection::setMomentum(const double& momentum)
{
#ifdef DEBUG
std::cout << "Connection::setMomentum" << std::endl;
#endif
this->momentum = momentum;
}
double Connection::getQ(void)
{
return Q;
}
void Connection::setQ(const double& _Q)
{
Q = _Q;
}
double Connection::getR(void)
{
return R;
}
void Connection::setR(const double& _R)
{
R = _R;
}
pNeuronX& Connection::getFrom(void)
{
#ifdef DEBUG
std::cout << "Connection::getFrom" << std::endl;
#endif
return from;
}
void Connection::setFrom(const pNeuronX& from)
{
#ifdef DEBUG
std::cout << "Connection::setFrom" << std::endl;
#endif
this->from = from;
}
pNeuronX& Connection::getTo(void)
{
#ifdef DEBUG
std::cout << "Connection::getTo" << std::endl;
#endif
return to;
}
void Connection::setTo(const pNeuronX& to)
{
#ifdef DEBUG
std::cout << "Connection::setTo" << std::endl;
#endif
this->to = to;
}
double Connection::randomizeWeight(void)
{
#ifdef DEBUG
std::cout << "Connection::randomizeWeight" << std::endl;
#endif
weight = rand() / double(RAND_MAX);
//deltaWeight = weight;
return weight;
}
void Connection::printOutput(void)
{
#ifdef DEBUG
std::cout << "Connection::printOutput" << std::endl;
#endif
if (!from)
return;
if (!to)
return;
int f = from->getIndex();
int t = to->getIndex();
//std::cout << " Connection[" << index << "] w=" << weight << ", From=" << f << ", To=" << t << ", d=" << deltaWeight << std::endl;
std::cout << " Connection[" << index << "] w=" << weight << ", From=" << f << ", To=" << t << ", d=" << deltaWeight << ", Q=" << Q << ", R=" << R << std::endl;
}
/*
#include
#include
#include
int random_number(int N) // random value in [0, N)
{
static std::random_device seed;
static std::mt19937 eng(seed());
std::uniform_int_distribution<> dist(0, N - 1);
return dist(eng);
}
std::vector random_sample(int first, int last, int n)
{
std::vector numbers;
int remaining = last - first + 1;
int m = std::min(n, remaining);
while (m > 0) {
if (random_number(remaining) < m) {
numbers.push_back(first);
--m;
}
--remaining;
++first;
}
return numbers;
}
int main()
{
auto numbers = random_sample(1, 100, 20);
for (int value : numbers) {
std::cout << value << " ";
}
std::cout << '\n';
}
*/
/*
very simple random is 1+((power(r,x)-1) mod p) will be from 1 to p for values of x from 1 to p and will be random where r and p are prime numbers and r <> p.
To shuffle an array a of n elements:
for i from n ? 1 downto 1 do
j ? random integer with 0 ? j ? i
exchange a[j] and a[i]
for (int i = cards.Length - 1; i > 0; i--)
{
int n = rand.Next(i + 1);
Swap(ref cards[i], ref cards[n]);
}
*/
connection.h
#ifndef __SHAREWIZ_CONNECTION_H__
#define __SHAREWIZ_CONNECTION_H__
//#include
//#include
// Connection class.
//
// A Connection links two Neurons.
class Neuron;
typedef std::shared_ptr pNeuronX;
typedef std::vector pNeuron;
class Connection
{
private:
int index;
double weight;
double deltaWeight;
double error;
double momentum; // alpha.
// For DQN.
// Should we re-use weight as Q and deltaWeight as R.
double Q;
double R;
double odds; // Odds of being chosen as next action for DQN.
double randomizeWeight(void);
pNeuronX from;
pNeuronX to;
public:
Connection();
Connection(const pNeuronX& from, const pNeuronX& to);
double getError(void);
void setError(const double& e);
int getIndex(void);
void setIndex(const int& index);
double getWeight(void);
void setWeight(const double& w);
double getDeltaWeight(void);
void setDeltaWeight(const double& w);
double getMomentum(void);
void setMomentum(const double& momentum);
double getQ(void);
void setQ(const double& _Q);
double getR(void);
void setR(const double& _R);
pNeuronX& getFrom(void);
void setFrom(const pNeuronX& from);
pNeuronX& getTo(void);
void setTo(const pNeuronX& to);
void printOutput(void);
};
#endif
layer.cpp
#include
#include
#include "layer.h"
#include "neuron.h"
#include "connection.h"
#include "activation.h"
//Layer::Layer() :
Layer::Layer()
// index(-1),
// neurons(10)
// index(0)
//neurons(10)
{
//idx++;
//index++;
index = -1;
neurons.reserve(10);
//neurons = std::vector();
//std::cout << "neurons size: " << neurons.size() << std::endl;
}
Layer::Layer(unsigned int num_neurons)
{
index = -1;
neurons.reserve(num_neurons);
for (unsigned int i = 0; isetIndex(i);
neurons.push_back(tmp);
}
/*
// Add a bias neuron in each layer.
// Force the bias node's output to 1.0 (it was the last neuron pushed in this layer):
pNeuronX tmp(new Neuron());
tmp->setIndex(100);
tmp->setValue(1);
neurons.push_back(tmp);
//neurons.back().back().setOutputVal(1.0);
//neurons.back()->setValue(1.0);
*/
}
int Layer::getIndex(void)
{
return index;
}
void Layer::setIndex(const int& index)
{
this->index = index;
}
unsigned int Layer::getSize(void)
{
return neurons.size();
}
void Layer::addNeuron(const pNeuronX& n)
{
neurons.push_back(n);
}
void Layer::removeNeuron(const int& idx)
{
assert(neurons.size() >= idx);
for (unsigned i = neurons.size()-1; i > 0; i--)
{
if (neurons[i]->getIndex() == idx)
{
neurons.erase(neurons.begin() + i);
return;
}
}
}
pNeuronX &Layer::getNeuron(const int& idx)
{
assert(neurons.size() >= idx);
return neurons[idx];
}
void Layer::feedForward(const pLayerX& prevLayer)
{
/*
// INPUT -> HIDDEN
for(y=0; y OUTPUT
for(y=0; ygetIndex();
for (unsigned int j = 0; jgetSize(); j++) // How many Neurons in prev layer.
{
pNeuronX& prevNeuron = prevLayer->getNeuron(j);
if (!prevNeuron)
continue;
//std::cout << "J=" << j << std::endl;
for (unsigned int k = 0; kgetSizeOut(); k++)
{
if (!prevNeuron->getConnectionOut(k))
continue;
if (!prevNeuron->getConnectionOut(k)->getTo())
continue;
// We are only interested in connections going into the currentNeuron.
unsigned int prevIndex = prevNeuron->getConnectionOut(k)->getTo()->getIndex();
//if (prevNeuron.getConnectionOut(k).getTo() == currentNeuron)
if (prevIndex == currentIndex)
{
weightedSum += prevLayer->getNeuron(j)->getValue()*prevLayer->getNeuron(j)->getConnectionOut(k)->getWeight();
}
}
}
// Add in Bias?
//weightedSum += .5; // Add a 1 to act as a bias.
//std::cout << "*************" << std::endl;
if (currentNeuron)
{
pActivationX act = currentNeuron->getActivation();
if (!act)
continue;
// Sigmoid function. Activation function is applied to this intermediate value to yield the local value of the neuron.
//currentNeuron->setValue(currentNeuron->sigmoid(weightedSum));
//currentNeuron->setValue(act.activate(weightedSum));
//currentNeuron->setValue(currentNeuron->getActivation()->activate(weightedSum));
currentNeuron->setValue(act->activate(weightedSum));
//std::cout << "------------------" << std::endl;
}
}
// std::cout << "++++++++++++++++" << std::endl;
}
void Layer::printOutput(void)
{
std::cout << "Layer " << index << " has " << neurons.size() << " Neurons" << std::endl;
for (unsigned int i = 0; i pLayerX;
typedef std::vector pLayer;
typedef std::shared_ptr pNeuronX;
typedef std::vector pNeuron;
class Layer
{
private:
int index;
pNeuron neurons;
public:
Layer();
Layer(unsigned int num_neurons);
unsigned int getSize(void); // Returns how many neurons.
int getIndex(void);
void setIndex(const int& index);
void addNeuron(const pNeuronX& n);
void removeNeuron(const int& idx);
pNeuronX& getNeuron(const int& idx);
void feedForward(const pLayerX& prevLayer);
void printOutput(void);
};
#endif
net.cpp
#include
#include
#include "net.h"
#include "layer.h"
#include "neuron.h"
#include "connection.h"
typedef std::shared_ptr pConnectionX;
typedef std::vector pConnection;
/*
It has been shown that the error surface of a backpropagation network with one hidden layer and hidden units
has no local minima, if the network is trained with an arbitrary set containing different inputs1 (Yu, 1992).
In practice, however, other features of the error surface such as "ravines" and "plateaus" (Baldi and Hornik, 1988)
can present difficulty for optimisation. For example, two error functions (from (Gori, 1996)) do not have local
minima. However, the function on the left is expected to be more difficult to optimise with gradient descent.
For the purposes of this paper, the criterion of interest considered is "the best solution found in a given
practical time limit.
*/
Net::Net() :
learning_rate(0.5),
max_error_tollerance(0.1),
goal_amount(100.0)
{
layers.reserve(10);
}
// Example:
// std::vector myTopology;
// myTopology.push_back(2);
// myTopology.push_back(4);
// myTopology.push_back(1);
// Net myNet(myTopology);
Net::Net(const std::vector& topology) :
learning_rate(0.5),
max_error_tollerance(0.1),
goal_amount(100.0)
{
assert(topology.size() > 0);
learning_rate = 0.5;
max_error_tollerance = 0.1;
goal_amount = 100.0;
layers.reserve(topology.size());
// obtain a time-based seed:
//unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
// using built-in random generator:
//shuffle (topology.begin(), topology.end(), std::default_random_engine(seed));
//auto engine = std::default_random_engine{};
//std::shuffle(std::begin(topology), std::end(topology), engine);
//std::random_shuffle ( topology.begin(), topology.end());
//std::shuffle ( topology.begin(), topology.end() );
for (unsigned int i = 0; isetIndex(i);
layers.push_back(tmp);
}
std::cout << "layers size: " << layers.size() << std::endl;
for (unsigned int i = 0; i < layers.size(); i++)
{
std::cout << "layers " << i << " neurons size: " << layers[i]->getSize() << std::endl;
}
//printOutput();
// Add Bias to input and hidden layers.
//layers[1]->addNeuron(
//connectAll();
//connectForward();
//printOutput();
}
// Connects the "From" Neuron to the "To" Neuron.
void Net::connect(const std::vector< std::vector > connections)
{
//unsigned int connection_idx = 1;
int connection_idx = 0;
for (unsigned int i = 0; i < connections.size(); i++)
{
//for (unsigned int j = 0; j < connections[i].size(); j++)
//{
int layerFrom = (int)connections[i][0];
int neuronFrom = (int)connections[i][1];
int layerTo = (int)connections[i][2];
int neuronTo = (int)connections[i][3];
double _R = connections[i][4];
pConnectionX tmp(new Connection(layers[layerFrom]->getNeuron(neuronFrom), layers[layerTo]->getNeuron(neuronTo)));
tmp->setIndex(connection_idx++);
tmp->setQ(0);
tmp->setR(_R);
layers[layerFrom]->getNeuron(neuronFrom)->addConnectionOut(tmp);
layers[layerTo]->getNeuron(neuronTo)->addConnectionIn(tmp);
//}
}
}
// Connects the "From" Neuron to the "To" Neuron.
void Net::connect(int layerFrom, int neuronFrom, int layerTo, int neuronTo, double _R, int connection_idx)
{
//unsigned int connection_idx = 1;
pConnectionX tmp(new Connection(layers[layerFrom]->getNeuron(neuronFrom), layers[layerTo]->getNeuron(neuronTo)));
tmp->setIndex(connection_idx);
tmp->setQ(0);
tmp->setR(_R);
layers[layerFrom]->getNeuron(neuronFrom)->addConnectionOut(tmp);
layers[layerTo]->getNeuron(neuronTo)->addConnectionIn(tmp);
}
// Connects all Neurons to each other.
void Net::connectAll()
{
// assert(layer.size() > 1); // There must be more than 1 neuron to connect.
int connection_idx = 0;
for (unsigned int i = 0; igetSize(); j++) // For each neuron in Sending Layer.
{
for (unsigned int k = 0; kgetSize(); l++) // For each neuron in Receiving layer.
{
pConnectionX tmp(new Connection(layers[i]->getNeuron(j), layers[k]->getNeuron(l)));
tmp->setIndex(connection_idx++);
layers[i]->getNeuron(j)->addConnectionOut(tmp);
layers[k]->getNeuron(l)->addConnectionIn(tmp);
//std::cout << "I[" << j << "] connected to H[" << k << "] with Connection IDX=" << connection_idx-1 << std::endl;
}
}
}
}
}
// Connects all Neurons in a layer to all Neurons in the next layer.
void Net::connectForward()
{
unsigned int connection_idx = 0;
for (unsigned int i = 0; igetSize(); j++) // how many input neurons in input level.
{
for (unsigned int k = 0; kgetSize(); k++) // how many neurons in next level.
{
pConnectionX tmp(new Connection(layers[i]->getNeuron(j), layers[i + 1]->getNeuron(k)));
tmp->setIndex(connection_idx++);
layers[i]->getNeuron(j)->addConnectionOut(tmp);
layers[i + 1]->getNeuron(k)->addConnectionIn(tmp);
//std::cout << "I[" << j << "] connected to H[" << k << "] with Connection IDX=" << connection_idx-1 << std::endl;
}
}
}
}
// Same as connectForward() but code spread out between layers.
// Connects all Neurons to Neurons in next layer.
void Net::connectForward2()
{
unsigned int connection_idx = 0;
// Create the input to hidden connections.
// assert(layers.size() > 1); // There must be more than 1 layers to connect.
for (unsigned int i = 0; i 1) // there are other layers
{
for (unsigned int j = 0; jgetSize(); j++) // how many input neurons in input level.
{
for (unsigned int k = 0; kgetSize(); k++) // how many neurons in next level.
{
pConnectionX tmp(new Connection(layers[0]->getNeuron(j), layers[1]->getNeuron(k)));
tmp->setIndex(connection_idx++);
layers[0]->getNeuron(j)->addConnectionOut(tmp);
layers[1]->getNeuron(k)->addConnectionIn(tmp);
//std::cout << "I[" << j << "] connected to H[" << k << "] with Connection IDX=" << connection_idx-1 << std::endl;
}
}
}
else // no other layers. so no connections possible.
{
}
}
// Create the inside hidden connections...and hidden to output connection.
if ((i>0) && (i <= layers.size() - 2))
{
for (unsigned int j = 0; jgetSize(); j++) // how many input neurons.
{
for (unsigned int k = 0; kgetSize(); k++) // how many neurons in next level.
{
pConnectionX tmp(new Connection(layers[i]->getNeuron(j), layers[i + 1]->getNeuron(k)));
tmp->setIndex(connection_idx++);
layers[i]->getNeuron(j)->addConnectionOut(tmp);
layers[i + 1]->getNeuron(k)->addConnectionIn(tmp);
//std::cout << "HI[" << j << "] connected to O[" << k << "] with Connection IDX=" << connection_idx-1 << std::endl;
}
}
}
}
}
// Connects all Neurons to each other.
void Net::connectAllInLayer(const pLayerX& layer)
{
// assert(layer.size() > 1); // There must be more than 1 neuron to connect.
unsigned int connection_idx = 0;
for (unsigned int i = 0; igetSize(); i++) // For each "from" neuron in Layer.
{
for (unsigned int j = 0; jgetSize(); j++) // For each "to" neuron in layer.
{
pConnectionX tmp(new Connection(layer->getNeuron(i), layer->getNeuron(j)));
tmp->setIndex(connection_idx++);
layer->getNeuron(i)->addConnectionOut(tmp);
layer->getNeuron(j)->addConnectionIn(tmp);
//std::cout << "I[" << j << "] connected to H[" << k << "] with Connection IDX=" << connection_idx-1 << std::endl;
}
}
}
void Net::DQN(void)
{
int numLayers = layers.size();
int numNeurons = 0;
int numConnections = 0;
// Determine how many layers, neurons (states) and connections (actions) we have.
for (unsigned int i = 0; i < layers.size(); i++) // get how many Layers
{
numNeurons += layers[i]->getSize();
for (unsigned int j = 0; j < layers[i]->getSize(); j++) // For each neuron in the Sending Layer.
{
pNeuronX& currentNeuron = layers[i]->getNeuron(j); // Get current neuron.
if (!currentNeuron)
continue;
numConnections += currentNeuron->getSizeOut(); // Get how many connections from the current neuron.
}
}
// Select random initial neuron (state).
int rnd_layer = randomBetween(0, numLayers-1);
int rnd_state = randomBetween(0, numNeurons-1);
pLayerX currentLayer = layers[rnd_layer];
pNeuronX currentState = layers[rnd_layer]->getNeuron(rnd_state);
// Set initial reward.
double R = -1;
// Loop until a reward matching the goal_amount has been found.
while (R != goal_amount)
{
// Select one amongst all possible actions for the current state.
// TODO: Simply using random treats all possible actions as equal.
// TODO: Should cater for giving different actions different odds of being chosen.
int rnd_action = randomBetween(0, currentState->getSizeOut()-1);
pConnectionX currentAction = currentState->getConnectionOut(rnd_action);
// Action outcome is set to deterministic in this example
// Transition probability is 1.
pNeuronX nextState = currentAction->getTo();
// Get reward.
R = currentAction->getR();
// Get Q.
double Q = currentAction->getQ();
// Determine the maximum Q.
double maxQ = DBL_MIN;
for (unsigned int i = 0; igetSizeOut(); i++)
{
double tmpQ = nextState->getConnectionOut(i)->getQ();
if (maxQ < tmpQ)
maxQ = tmpQ;
}
if (maxQ == DBL_MIN) maxQ = 0;
// Update the Q.
//double v = Q + alpha * (R + gamma * maxQ - Q);
double target = R + gamma * maxQ;
//double error = R + gamma * maxQ - Q;
double error = target - Q;
// Experience Replay Memory.
// To suggest an experience replay memory.
// This is loosely inspired by the brain, and in particular the way it syncs memory traces in the hippocampus
// with the cortex.
// What this amounts to is that instead of performing an update and then throwing away the experience tuple,
// i.e. the original Q, we keep it around and effectively build up a training set of experiences.
// Then, we don't learn based on the new experience that comes in at time t, but instead sample random
// expriences from the replay memory and perform an update on each sample.
// This feature has the effect of removing correlations in the observed state,action,reward sequence and
// reduces gradual drift and forgetting.
// If the size of the memory pool is greater than some threshold, start replacing old experiences.
// or those further from the current Q, or randomly etc.
int rnd_replay_memory = randomBetween(0, 100);
if (rnd_replay_memory > 99) // if rnd > some value
{
//experience_add_every = 5; // number of time steps before we add another experience to replay memory.
//experience_size = 10000; // size of experience.
// Record old Q value into array of stored memories.
// Now select new Q value from randomly selecting one of the old Q memory values - perhaps by using odds.
// i.e. most fresh Q value might have slightly greater chance of being selected etc.
}
// Clamping TD Error.
// Clamp the TD Error gradient at some fixed maximum value.
// If the error is greater in magnitude then some threshold (tderror_clamp) then we cap it at that value.
// This makes the learning more robust to outliers and has the interpretation of using Huber loss, which
// is an L2 penalty in a small region around the target value and an L1 penalty further away.
// double tderror_clamp = 1.0; // for robustness
// if (error > tderror_clamp)
// error = tderror_clamp;
// Periodic Target Q Value Updates.
// Periodically freeze the Q where it is.
// Aims to reduce correlations between updates and the immediately undertaken behavior.
// The idea is to freeze the Q network once in a while into a frozen, copied network, which is used to
// only compute the targets.
// This target network is once in a while updated to the actual current.
int rnd_freeze = randomBetween(0, 100);
if (rnd_freeze > 99)
{
}
double v = Q + alpha * (error);
currentAction->setQ(v);
// Update the state.
currentState = nextState;
}
}
// Determine the maximum Q for the state.
double Net::getMaxQ(pNeuronX state)
{
double maxQ = DBL_MIN;
for (unsigned int i = 0; igetSizeOut(); i++)
{
double tmpQ = state->getConnectionOut(i)->getQ();
if (maxQ < tmpQ)
maxQ = tmpQ;
}
if (maxQ == DBL_MIN)
maxQ = 0;
return maxQ;
}
// Get policy from state.
pNeuronX Net::getPolicy(pNeuronX currentState)
{
double maxValue = DBL_MIN;
pNeuronX policyGotoState = currentState; // Default goto self if not found.
for (unsigned int i = 0; i < currentState->getSizeOut(); i++)
{
pNeuronX nextState = currentState->getConnectionOut(i)->getTo();
double value = currentState->getConnectionOut(i)->getQ();
if (value > maxValue)
{
maxValue = value;
policyGotoState = nextState;
}
}
return policyGotoState;
}
// Policy is maxQ(states).
void Net::showPolicy(void)
{
for (unsigned int i = 0; i < layers.size(); i++)
{
for (unsigned int j = 0; j < layers[i]->getSize(); j++)
{
pNeuronX fromState = layers[i]->getNeuron(j);
int from = fromState->getIndex();
pNeuronX toState = getPolicy(fromState);
int to = toState->getIndex();
std::cout << "From " << from << " goto " << to << std::endl;
}
}
}
// This method has a bit of a bias towards the low end if the range of rand() isn't divisible
// by highestNumber - lowestNumber + 1.
int Net::randomBetween(int lowestNumber, int highestNumber)
{
assert(highestNumber >= lowestNumber);
//return rand() % to + from;
return rand() % (highestNumber - lowestNumber + 1) + lowestNumber;
}
// Controls how much the weights are changed during a weight update.
// The larger the value, the more the weights are changed.
// This must be a real value between 0.0 and 10.0.
// These values are commonly set from 0.5 to 0.7.
double Net::getLearningRate(void)
{
return learning_rate;
}
void Net::setLearningRate(const double& learning_rate)
{
this->learning_rate = learning_rate;
}
double Net::getMaxErrorTollerance(void)
{
return max_error_tollerance;
}
void Net::setMaxErrorTollerance(const double& max_error_tollerance)
{
this->max_error_tollerance = max_error_tollerance;
}
double Net::getAlpha(void)
{
return alpha;
}
// Learning rate.
//
// The Alpha parameter has a range of 0 to 1 (0 <= Gamma > 1).
//
// Set this by trial and error. That's Pretty much the best thing we have.
void Net::setAlpha(const double& _alpha_amount)
{
alpha = _alpha_amount;
}
double Net::getGamma(void)
{
return gamma;
}
// Discount factor.
//
// The Gamma parameter has a range of 0 to 1 (0 <= Gamma > 1).
//
// If Gamma is closer to zero, the agent will tend to consider only immediate rewards.
//
// If Gamma is closer to one, the agent will consider future rewards with greater weight,
// willing to delay the reward.
void Net::setGamma(const double& _gamma_amount)
{
gamma = _gamma_amount;
}
double Net::getGoalAmount(void)
{
return goal_amount;
}
void Net::setGoalAmount(const double& _goal_amount)
{
this->goal_amount = _goal_amount;
}
/*
void Net::load_data(char *arg)
{
int x, y;
ifstream in(arg);
if(!in)
{
cout << endl << "failed to load data file" << endl; file_loaded = 0;
return;
}
in >> input_array_size;
in >> hidden_array_size;
in >> output_array_size;
in >> learning_rate;
in >> number_of_input_patterns;
bias_array_size = hidden_array_size + output_array_size;
initialize_net();
for (x=0; x> bias[x];
for(x=0; x> weight_i_h[x][y];
}
for(x=0; x> weight_h_o[x][y];
}
for(x=0; x> input[x][y];
}
for(x=0; x> target[x][y];
}
in.close();
cout << endl << "data loaded" << endl;
return;
}
void Net::save_data(char *argres)
{
int x, y;
ofstream out;
out.open(argres);
if(!out)
{
cout << endl << "failed to save file" << endl;
return;
}
out << input_array_size << endl;
out << hidden_array_size << endl;
out << output_array_size << endl;
out << learning_rate << endl;
out << number_of_input_patterns << endl << endl;
for(x=0; xgetNeuron(0)->setValue(1);
layers[0]->getNeuron(1)->setValue(1);
//layers[0]->getNeuron(2)->setValue(1);
layers[1]->getNeuron(0)->setValue(123);
layers[1]->getNeuron(1)->setValue(456);
layers[2]->getNeuron(0)->setValue(0);
layers[0]->getNeuron(0)->getConnectionOut(0)->setWeight(0.1);
layers[0]->getNeuron(0)->getConnectionOut(1)->setWeight(0.2);
layers[0]->getNeuron(1)->getConnectionOut(0)->setWeight(0.3);
layers[0]->getNeuron(1)->getConnectionOut(1)->setWeight(0.4);
layers[1]->getNeuron(0)->getConnectionOut(0)->setWeight(0.5);
layers[1]->getNeuron(1)->getConnectionOut(0)->setWeight(0.6);
// Add connection between two neurons in same level 1
//pConnectionX tmp(new Connection(layers[1]->getNeuron(0), layers[1]->getNeuron(1)));
//tmp->setIndex(100);
//layers[1]->getNeuron(0)->addConnectionOut(tmp);
printOutput();
//layers[1]->getNeuron(0)->removeConnectionOut(0)->setWeight(0.5);
//layers[1]->getNeuron(0)->getConnectionOut(0) = nullptr;
//layers[1]->getNeuron(0)->getConnectionIn(0) = nullptr;
//layers[0]->getNeuron(0)->getConnectionOut(0) = nullptr;
//layers[0]->getNeuron(0)->getConnectionOut(1) = nullptr;
//layers[0]->getNeuron(0) = nullptr;
printOutput();
std::cout << "**************************************************************" << std::endl;
}
// TODO: Only works if 3 or more layers. Perhaps we should cater when zero hidden layers?
void Net::feedForward(const std::vector& inputVals)
{
// std::cout << "inputVals.size=" << inputVals.size() << std::endl;
// std::cout << "layers[0]->getSize()=" << layers[0]->getSize() << std::endl;
assert(layers[0]->getSize() == inputVals.size());
//std::cout << "inputVals.size=" << inputVals.size() << std::endl;
// Setting input vals to input layer.
for (unsigned int i = 0; igetNeuron(i))
continue;
layers[0]->getNeuron(i)->setValue(inputVals[i]); // layers[0] is the input layer.
}
// Updating hidden layers.
for (unsigned int i = 1; ifeedForward(layers[i - 1]); // Updating the neurons output based on the neurons of the previous layer.
}
// Updating output layer.
for (unsigned int i = 0; igetSize(); i++) // How many neurons in the output layer
{
pLayerX& prevLayer = layers[layers.size() - 2];
layers[layers.size() - 1]->feedForward(prevLayer); // Updating the neurons output based on the neurons of the previous layer.
}
}
/*
void backward_pass(int pattern)
{
register int x, y;
register double temp = 0;
// COMPUTE ERRORSIGNAL FOR OUTPUT UNITS
for(x=0; x& targetVals)
{
// COMPUTE ERRORSIGNAL FOR OUTPUT UNITS
pLayerX& outputLayer = layers.back();
assert(targetVals.size() == outputLayer->getSize());
// Traversing output layer.
for (unsigned int i = 0; igetSize(); i++) // For every output Neuron.
{
if (!outputLayer->getNeuron(i))
continue;
double outputValue = outputLayer->getNeuron(i)->getValue();
double gradient = (targetVals[i] - outputValue) * outputValue * (1.0 - outputValue);
outputLayer->getNeuron(i)->setGradient(gradient);
}
// COMPUTE ERRORSIGNAL FOR HIDDEN UNITS
for (unsigned int i = layers.size() - 2; i>0; i--) // for every hidden layer
{
pLayerX& currentLayer = layers[i];
pLayerX& nextLayer = layers[i + 1];
for (unsigned int j = 0; jgetSize(); j++) // for every neuron
{
double temp = 0.0;
pNeuronX& currentNeuron = layers[i]->getNeuron(j); // current neuron.
if (!currentNeuron)
continue;
for (unsigned int k = 0; kgetSizeOut(); k++) // for every connection in current layer.
{
pConnectionX ¤tConnection = currentNeuron->getConnectionOut(k);
if (!currentConnection)
continue;
if (!currentConnection->getTo())
continue;
int currentIndex = currentNeuron->getConnectionOut(k)->getTo()->getIndex();
for (unsigned int l = 0; lgetSize(); l++) // for every neuron in next layer
{
pNeuronX& nextNeuron = nextLayer->getNeuron(l); // next layers neuron.
if (!nextNeuron)
continue;
int nextIndex = nextNeuron->getIndex();
if (currentIndex == nextIndex)
{
temp += (nextNeuron->getGradient() * currentConnection->getWeight()); // output_error + weight-h-o
}
}
}
currentNeuron->setGradient(currentNeuron->getValue() * (1.0 - currentNeuron->getValue()) * temp);
}
}
// ADJUST WEIGHTS OF CONNECTIONS FROM HIDDEN TO OUTPUT UNITS
for (unsigned int i = 0; igetSize(); j++) // for every neuron.
{
pNeuronX& currentNeuron = layers[i]->getNeuron(j);
if (!currentNeuron)
continue;
double currentValue = currentNeuron->getValue();
for (unsigned int k = 0; kgetNeuron(j)->getSizeOut(); k++) // for every connection.
{
pConnectionX& currentConnection = currentNeuron->getConnectionOut(k);
if (!currentConnection)
continue;
pNeuronX& nextNeuron = currentConnection->getTo();
if (!nextNeuron)
continue;
double nextGradient = nextNeuron->getGradient();
//double delta = 0.5 * nextGradient * currentNeuron->getValue();
double delta = 0.5 * nextGradient * currentValue;
//currentConnection->setWeight(currentConnection->getWeight() + delta + (0.4 * currentConnection->getDeltaWeight()));
currentConnection->setWeight(currentConnection->getWeight() + delta + (currentConnection->getMomentum() * currentConnection->getDeltaWeight()));
currentConnection->setDeltaWeight(delta);
}
}
}
}
void Net::backPropagate2(const std::vector& targetVals)
{
pLayerX& outputLayer = layers.back();
//assert(targetVals.size() == outputLayer.size());
assert(targetVals.size() == outputLayer->getSize());
// Starting with the output layer.
//for (unsigned int i=0; igetSize(); i++) // How many neurons in output layer.
{
pNeuronX& currentNeuron = outputLayer->getNeuron(i);
double output = outputLayer->getNeuron(i)->getValue();
// COMPUTE ERRORSIGNAL FOR OUTPUT UNITS
double error = output * (1 - output) * (pow(targetVals[i] - output, 2)); // std::cout << "good4" << std::endl;
//std::cout << "Error Output=" << error << std::endl;
// ADJUST WEIGHTS OF CONNECTIONS FROM HIDDEN TO OUTPUT UNITS
for (unsigned int j = 0; jgetNeuron(i)->getSizeIn(); j++)
{
outputLayer->getNeuron(i)->getConnectionIn(j)->setError(error); // Set error against each connection into the output layer.
double newWeight = outputLayer->getNeuron(i)->getConnectionIn(j)->getWeight();
newWeight += (error * outputLayer->getNeuron(i)->getValue());
outputLayer->getNeuron(i)->getConnectionIn(j)->setWeight(newWeight); // Setting new weight of each connection into the output layer.
}
}
for (unsigned int i = layers.size() - 2; i>0; i--) // Traversing hidden layers all the way to input layer.
{
pLayerX& currentLayer = layers[i];
pLayerX& nextLayer = layers[i + 1];
// Traversing current layer
//for (unsigned int j=0; jgetSize(); j++) // for every neuron in current layer.
{
const double& output = currentLayer->getNeuron(j)->getValue(); // get its value.
double subSum = 0.0; // Initializing subsum.
// Traversing next layer.
for (unsigned int k = 0; kgetSize(); k++) // for every neuron in next layer.
{
double error = nextLayer->getNeuron(k)->getConnectionIn(k)->getError();
double weight = nextLayer->getNeuron(k)->getConnectionIn(j)->getWeight();
//subSum += pow(nextLayer.getNeuron(j).getConnectionIn(k).getError() * currentLayer.getNeuron(j).getConnectionIn(k).getWeight(),2); // Getting their backpropagated error and weight.
subSum += pow(nextLayer->getNeuron(k)->getConnectionIn(k)->getError() * currentLayer->getNeuron(j)->getConnectionIn(k)->getWeight(), 2); // Getting their backpropagated error and weight.
//subSum += pow(nextLayer.getNeuron(k).getConnectionIn(k).getError() * nextLayer.getNeuron(k).getConnectionIn(j).getWeight(),2); // Getting their backpropagated error and weight.
}
double error = output*(1 - output)*(subSum);
for (unsigned int k = 0; kgetNeuron(j)->getSizeIn(); k++)
{
currentLayer->getNeuron(j)->getConnectionIn(k)->setError(error);
double newWeight = currentLayer->getNeuron(j)->getConnectionIn(k)->getWeight();
newWeight += error * output;
currentLayer->getNeuron(j)->getConnectionIn(k)->setWeight(newWeight);
}
}
}
}
//void Net::printOutput(void) const
void Net::printOutput(void)
{
std::cout << "***Net has [" << layers.size() << "] layers" << std::endl;
for (unsigned int i = 0; iprintOutput();
}
}
void Net::printResult(void)
{
pLayerX& outputLayer = layers.back();
for (unsigned int i = 0; igetSize(); i++)
{
std::cout << "Result=" << outputLayer->getNeuron(i)->getValue() << std::endl;
}
}
void Net::setTarget(const std::vector& targetVals)
{
}
net.h
#ifndef __SHAREWIZ_NET_H__
#define __SHAREWIZ_NET_H__
#include
#include
// A Net class.
//
// To handle neural networks.
// There are several things to keep in mind when applying this agent in practice :
// 1. If the rewards are very sparse in the environment the agent will have trouble learning.
// Right now there is no priority sweeping support, but one might imagine oversampling experience that have
// high TD errors. It's not clear how this can be done in most principled way.
// Similarly, there are no eligibility traces right now though this could be added with a few modifications
// in future versions.
// 2. The exploration is rather naive, since a random action is taken once in a while.
// If the environment requires longer sequences of precise actions to get a reward, the agent might have a
// lot of difficulty finding these by chance, and then also learning from them sufficiently.
// 3. DQN only supports a set number of discrete actions and it is not obvious how one can incorporate
// (high - dimensional) continuous action spaces.
class Layer;
typedef std::shared_ptr pLayerX;
typedef std::vector pLayer;
class Neuron;
typedef std::shared_ptr pNeuronX;
typedef std::vector pNeuron;
class Net
{
private:
//std::vector& targetVals;
double learning_rate; // eta.
// Controls how much the weights are changed during a weight update.
// The larger the value, the more the weights are changed.
// This must be a real value between 0.0 and 10.0.
// These values are commonly set from 0.5 to 0.7.
double max_error_tollerance;
double alpha = 0.1; // Learning rate.
// Set this by trial and error. That's Pretty much the best thing we have.
double gamma = 0.4; // Discount factor (0 - 1).
// If Gamma is closer to 0, the agent will tend to consider only
// immediate rewards.
// If Gamma is closer to 1, the agent will consider future rewards
// with greater weight, willing to delay the reward.
//double epsilon = 0.2; // Initial epsilon for epsilon-greedy policy (0 - 1).
// High epsilon(up to 1) will cause the agent to take more random actions.
// It is a good idea to start with a high epsilon(e.g. 0.2 or even a bit higher)
// and decay it over time to be lower(e.g. 0.05).
//double lambda = 0; // eligibility trace decay, [0,1). 0 = no eligibility traces.
double goal_amount; // Used by DQN networks. The goal amount to try to obtain.
pLayer layers;
public:
Net();
Net(const std::vector& topology);
double getLearningRate(void);
void setLearningRate(const double& learning_rate);
double getMaxErrorTollerance(void);
void setMaxErrorTollerance(const double& max_error_tollerance);
double getAlpha(void);
void setAlpha(const double& _alpha_amount);
double getGamma(void);
void setGamma(const double& _gamma_amount);
double getGoalAmount(void);
void setGoalAmount(const double& _goal_amount);
void setTarget(const std::vector& targetVals);
void setTest();
void connect(const std::vector< std::vector > connections);
void connect(int layerFrom, int neuronFrom, int layerTo, int neuronTo, double _R, int connection_idx = 1);
void connectAll();
void connectForward();
void connectForward2();
void connectAllInLayer(const pLayerX& layer);
void DQN(void);
double getMaxQ(pNeuronX state);
pNeuronX getPolicy(pNeuronX currentState);
void showPolicy(void);
void feedForward(const std::vector& inputVals);
void backPropagate(const std::vector& targetVals);
void backPropagate2(const std::vector& targetVals);
int randomBetween(int lowestNumber, int highestNumber);
void printOutput(void);
void printResult(void);
};
#endif
neuron.cpp
#include
#include
#include "neuron.h"
#include "connection.h"
Neuron::Neuron()
{
#ifdef DEBUG
std::cout << "Neuron::Neuron" << std::endl;
#endif
index = -1;
gradient = 0;
value = 0;
connections_in.reserve(10);
connections_out.reserve(10);
pActivationX tmp(new Activation());
//pActivationX tmp(new Activation(ACTIVATION_SQRT));
this->activation = tmp;
//activation_type = ACTIVATION_SIGMOID;
randomizeValue();
}
bool Neuron::operator==(Neuron& rhs) const
{
//cout << "operator overloaded == " << rhs.name;
if (this->index==rhs.index)
//if (*this == rhs)
return true;
return false;
}
double Neuron::getGradient(void)
{
#ifdef DEBUG
std::cout << "Neuron::getGradient" << std::endl;
#endif
return gradient;
}
void Neuron::setGradient(const double& gradient)
{
#ifdef DEBUG
std::cout << "Neuron::setGradient" << std::endl;
#endif
this->gradient = gradient;
}
int Neuron::getIndex(void)
{
#ifdef DEBUG
std::cout << "Neuron::getIndex" << std::endl;
#endif
return index;
}
void Neuron::setIndex(const int& index)
{
#ifdef DEBUG
std::cout << "Neuron::setIndex" << std::endl;
#endif
this->index = index;
}
unsigned int Neuron::getSizeIn(void)
{
#ifdef DEBUG
std::cout << "Neuron::getSizeIn" << std::endl;
#endif
return connections_in.size();
}
unsigned int Neuron::getSizeOut(void)
{
#ifdef DEBUG
std::cout << "Neuron::getSizeOut" << std::endl;
#endif
return connections_out.size();
}
double Neuron::getValue(void)
{
#ifdef DEBUG
std::cout << "Neuron::getValue" << std::endl;
#endif
return value;
}
void Neuron::setValue(const double& v)
{
#ifdef DEBUG
std::cout << "Neuron::setValue" << std::endl;
#endif
value = v;
}
void Neuron::addConnectionIn(const pConnectionX& c)
{
#ifdef DEBUG
std::cout << "Neuron::addConnectionIn" << std::endl;
#endif
connections_in.push_back(c);
//index++;
}
//void Neuron::addConnectionOut(const shared_ptr& c)
void Neuron::addConnectionOut(const pConnectionX& c)
{
#ifdef DEBUG
std::cout << "Neuron::addConnectionOut" << std::endl;
#endif
connections_out.push_back(c);
//index++;
}
// Returns a specific input connection.
pConnectionX &Neuron::getConnectionIn(const unsigned int& idx)
{
#ifdef DEBUG
std::cout << "Neuron::getConnectionIn" << std::endl;
#endif
assert(connections_in.size() >= idx);
return connections_in[idx];
}
// Returns a specific output connection.
pConnectionX &Neuron::getConnectionOut(const unsigned int& idx)
{
#ifdef DEBUG
std::cout << "Neuron::getConnectionOut" << std::endl;
#endif
assert(connections_out.size() >= idx);
return connections_out[idx];
}
// Remove all connections with a value below the indicated threshold.
//
// TODO: Should we consider abs value?
void Neuron::pruneConnectionIn(const double& threshold)
{
for (unsigned i = connections_in.size()-1; i > 0; i--)
{
if (connections_in[i]->getWeight() < threshold)
{
// TODO. Do we need to also remove the "From" and "To" elements of Neurons manually or will these auto remove?
// TODO. Does this retain the actual Connection, which potentially we should potentially delete if not used?
connections_in.erase(connections_in.begin() + i);
}
}
}
// Remove all connections with a value below the indicated threshold.
//
// TODO: Should we consider abs value?
void Neuron::pruneConnectionOut(const double& threshold)
{
for (unsigned i = connections_out.size()-1; i > 0; i--)
{
if (connections_out[i]->getWeight() < threshold)
{
// TODO. Do we need to also remove the "From" and "To" elements of Neurons manually or will these auto remove?
// TODO. Does this retain the actual Connection, which potentially we should potentially delete if not used?
connections_out.erase(connections_out.begin() + i);
}
}
}
void Neuron::removeConnectionIn(const unsigned int& idx)
{
#ifdef DEBUG
std::cout << "Neuron::removeConnectionIn" << std::endl;
#endif
assert(connections_in.size() >= idx);
//for (unsigned i = 0; i < connections_in.size(); i++)
for (unsigned i = connections_in.size()-1; i > 0; i--)
{
if (connections_in[i]->getIndex() == idx)
{
connections_in.erase(connections_in.begin() + i);
return;
}
}
}
void Neuron::removeConnectionOut(const unsigned int& idx)
{
#ifdef DEBUG
std::cout << "Neuron::removeConnectionOut" << std::endl;
#endif
assert(connections_out.size() >= idx);
//for (unsigned i = 0; i < connections_out.size(); i++)
for (unsigned i = connections_out.size()-1; i > 0; i--)
{
if (connections_out[i]->getIndex() == idx)
{
connections_out.erase(connections_out.begin() + i);
return;
}
}
}
double Neuron::randomizeValue(void)
{
#ifdef DEBUG
std::cout << "Neuron::randomizeValue" << std::endl;
#endif
value = rand() / double(RAND_MAX);
return value;
}
pActivationX &Neuron::getActivation(void)
{
return activation;
}
Activation_Types Neuron::getActivationType()
{
return activation->getActivationType();
}
void Neuron::setActivationType(Activation_Types _activation_type)
{
//activation_type = _activation_type;
activation->setActivationType(_activation_type);
}
/*
// Return random double between -0.5 and +0.5.
double Neuron::randf()
{
#ifdef DEBUG
std::cout << "Neuron::randf" << std::endl;
#endif
double r = ((double)rand()) / double(RAND_MAX);
return r - 0.5;
}
*/
// Returns a value between 0.0 and 1.0.
double Neuron::sigmoid(const double& weightedSum)
{
#ifdef DEBUG
std::cout << "Neuron::sigmoid" << std::endl;
#endif
return 1.0 / double((1.0 + exp(-weightedSum)));
}
double Neuron::sigmoid_derivative(const double& x)
{
#ifdef DEBUG
std::cout << "Neuron::sigmoid_derivative" << std::endl;
#endif
return sigmoid(x) * (1.0 - sigmoid(x));
}
double Neuron::sigmoidX(double x)
{
#ifdef DEBUG
std::cout << "Neuron::sigmoidX" << std::endl;
#endif
if (x < -45.0)
return 0.0;
else
if (x > 45.0)
return 1.0;
else
return 1.0 / (1.0 + exp(-x));
}
// Returns a value between -1.0 and +1.0.
double Neuron::hyperTanFunction(double& x)
{
#ifdef DEBUG
std::cout << "Neuron::hyperTanFunction" << std::endl;
#endif
if (x < -10.0)
return -1.0;
else
if (x > 10.0)
return 1.0;
else
return tanh(x);
}
double Neuron::tanh_derivative(const double& x)
{
#ifdef DEBUG
std::cout << "Neuron::tanh_derivative" << std::endl;
#endif
return (1.0 - tanh(x)) * (1.0 + tanh(x));
}
/*
double Neuron::transferFunction(double x)
{
// tanh - output range [-1.0..1.0]
return tanh(x);
}
double Neuron::transferFunctionDerivative(double x)
{
// tanh derivative
return 1.0 - x * x;
}
*/
void Neuron::printOutput(void)
{
#ifdef DEBUG
std::cout << "Neuron::printOutput" << std::endl;
#endif
std::cout << "Neuron[" << index << "] = " << value << " . It has " << connections_in.size() << " Connections-In, and "
<< connections_out.size() << " Connections-Out" << std::endl;
for (unsigned int i = 0; i pConnectionX;
typedef std::vector pConnection;
class Neuron
{
private:
int index;
double value;
double gradient; // How far off, and in what direction (positive or negative), local value are relative to the target outputs.
pConnection connections_in;
pConnection connections_out;
pActivationX activation;
public:
Neuron();
bool operator==(Neuron& rhs) const;
unsigned int getSizeIn(void); // Returns how many connections.
unsigned int getSizeOut(void); // Returns how many connections.
void addConnectionIn(const pConnectionX& c);
void addConnectionOut(const pConnectionX& c);
pConnectionX &getConnectionIn(const unsigned int& idx);
pConnectionX &getConnectionOut(const unsigned int& idx);
void pruneConnectionIn(const double& threshold); // Remove all synapses with a value below the indicated threshold.
void pruneConnectionOut(const double& threshold); // Remove all synapses with a value below the indicated threshold.
void removeConnectionIn(const unsigned int& idx);
void removeConnectionOut(const unsigned int& idx);
double getGradient(void);
void setGradient(const double& gradient);
int getIndex(void);
void setIndex(const int& index);
double getValue(void);
void setValue(const double& v);
double randomizeValue(void);
pActivationX &getActivation(void);
Activation_Types getActivationType();
void setActivationType(Activation_Types _activation_type);
double sigmoid(const double& weightedSum);
double sigmoid_derivative(const double& x);
double sigmoidX(double x);
double hyperTanFunction(double& x);
double tanh_derivative(const double& x);
void printOutput(void);
};
#endif
neuron_group.cpp
#include
#include
#include "neuron_group.h"
#include "neuron.h"
#include "connection.h"
NeuronGroup::NeuronGroup()
{
index = -1;
neurons.reserve(10);
}
NeuronGroup::NeuronGroup(unsigned int num_neurons)
{
index = -1;
neurons.reserve(num_neurons);
for (unsigned int i = 0; i < num_neurons; i++)
{
pNeuronX tmp(new Neuron());
tmp->setIndex(i);
neurons.push_back(tmp);
}
}
int NeuronGroup::getIndex(void)
{
return index;
}
void NeuronGroup::setIndex(const int& index)
{
this->index = index;
}
unsigned int NeuronGroup::getSize(void)
{
return neurons.size();
}
void NeuronGroup::addNeuron(const pNeuronX& n)
{
neurons.push_back(n);
}
void NeuronGroup::removeNeuron(const int& idx)
{
assert(neurons.size() >= idx);
for (unsigned i = neurons.size() - 1; i > 0; i--)
{
if (neurons[i]->getIndex() == idx)
{
neurons.erase(neurons.begin() + i);
return;
}
}
}
pNeuronX &NeuronGroup::getNeuron(const int& idx)
{
assert(neurons.size() >= idx);
return neurons[idx];
}
void NeuronGroup::printOutput(void)
{
std::cout << "Layer " << index << " has " << neurons.size() << " Neurons" << std::endl;
for (unsigned int i = 0; i
std::string numberToString(T pNumber)
{
std::ostringstream oOStrStream;
oOStrStream << pNumber;
return oOStrStream.str();
}
#include
#include
// Returns all occurences of the regex within the string.
//
// Example:
// std::string regex = "([A-Z]+)([\\d]+)";
// std::string ss = "aaaMAY14bbbJUNE4";
//
// Returns:
// [0]=MAY14#
// [1]=JUNE4#
std::vector string_find(const std::string& s, const std::string& regex)
{
std::vector result;
std::regex reg(regex);
//std::sregex_token_iterator it(s.begin(), s.end(), reg, { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
//std::sregex_token_iterator it(s.begin(), s.end(), reg, { 1, 0 });
// The 4th param indicates:
// -1 would indicate to return all none-occurences.
// 0 indicates to return all occurences found.
// 1 would return all the 1st sub-expression occurences.
// 2 would return all the 2nd sub-expression occurences.
// 3...
std::sregex_token_iterator it(s.begin(), s.end(), reg, 0);
std::sregex_token_iterator reg_end;
for (int i=0; it != reg_end; ++it, i++)
{
//std::cout << "[" << i << "]=" << it->str() << "#" << std::endl;
//std::cout << "[" << i << "]=" << *it << "#" << std::endl;
result.push_back(*it);
}
return result;
}
// Replaces all occurences of the regex within the replacement string.
//
// Parameters:
//
// replacement:
// The replacement string may contain references of the form $n. Every such reference will be replaced by the
// text captured by the n'th parenthesized pattern.
// n can be from 0 to 99, and $0 refers to the text matched by the whole pattern.
//
// This may include format specifiers and escape sequences that are replaced by the characters they represent.
//
// For format_default, the possible specifiers are:
// $n n-th backreference(i.e., a copy of the n-th matched group specified with parentheses in the regex pattern).
// n must be an integer value designating a valid backreference, greater than 0, and of two digits at most.
// $& A copy of the entire match
// $` The prefix(i.e., the part of the target sequence that precedes the match).
// $' The suffix(i.e., the part of the target sequence that follows the match).
// $$ A single $ character.
//
// flags:
// One or more of these constants can be combined (using the bitwise OR operator, |) to
// form a valid bitmask value of type regex_constants::match_flag_type:
//
// flag effects notes
// ------------------
// match_default Default Default matching behavior. This constant has a value of zero**.
// match_not_bol Not Beginning-Of-Line The first character is not considered a beginning of line("^" does not match).
// match_not_eol Not End-Of-Line The last character is not considered an end of line("$" does not match).
// match_not_bow Not Beginning-Of - Word The escape sequence "\b" does not match as a beginning-of-word.
// match_not_eow Not End-Of-Word The escape sequence "\b" does not match as an end-of-word.
// match_any Any match Any match is acceptable if more than one match is possible.
// match_not_null Not null Empty sequences do not match.
// match_continuous Continuous The expression must match a sub-sequence that begins at the first character.
// Sub-sequences must begin at the first character to match.
// match_prev_avail Previous Available One or more characters exist before the first one. (match_not_bol and match_not_bow are ignored).
// format_default Default formatting Uses the standard formatting rules to replace matches(those used by ECMAScript's replace method).
// This constant has a value of zero**.
// format_sed sed formatting Uses the same rules as the sed utility in POSIX to replace matches.
// format_no_copy No copy The sections in the target sequence that do not match the regular expression are not copied when replacing matches.
// format_first_only First only Only the first occurrence of a regular expression is replaced.
//
// NOTE: ** Constants with a value of zero are ignored if some other flag is set.
//
// Example:
// std::string s("This is a catfish");
// std::string regex("(cat)");
// std::string replacement("(dog)");
//
// result = string_replace(ss, regex, "dog");
//
// Returns:
// This is a dogfish.
//
// Example2:
// std::string regex("([A-Za-z]+)&([A-Za-z]+)"); // Find word&word
// std::string replacement = "$2&$1"; // Switch order.
//
// result = string_replace(s, regex, replacement);
//
// Example3:
// std::string s = "April 15, 2003";
// std::string regex = "(\\w+) (\\d+), (\\d+)";
// std::string result = string_replace(ss, regex, "$011,$3");
//
// Returns:
// April1,2003.
//
// NOTE: Isolated $1 backreferences.
// The $011 says to use $01, or the 1st regex match.
// If $11 was used, the system would try to use the 11th regex match.
// This only works because the limit of set to 99 maximum matches.
//
// Example4:
// result = string_replace(ss, regex, "dog", std::regex_constants::format_first_only);
std::string string_replace(const std::string& s, const std::string& regex, const std::string& replacement,
std::regex_constants::match_flag_type flags)
{
std::string result = s;
std::regex reg(regex);
// using string/c-string (3) version:
result = std::regex_replace(result, reg, replacement, flags);
/*
// using string/c-string (3) version:
std::cout << std::regex_replace(s3, e, "sub-$2");
// using range/c-string (6) version:
std::string result2;
std::regex_replace(std::back_inserter(result2), s3.begin(), s3.end(), e, "$2");
std::cout << result2;
// with flags:
std::cout << std::regex_replace(s3, e, "$1 and $2", std::regex_constants::format_no_copy);
std::cout << std::endl;
*/
return result;
}
// Replaces all occurences of the regex within the replacement string.
//
// Parameters:
//
// replacement:
// The replacement string may contain references of the form $n. Every such reference will be replaced by the
// text captured by the n'th parenthesized pattern.
// n can be from 0 to 99, and $0 refers to the text matched by the whole pattern.
//
// This may include format specifiers and escape sequences that are replaced by the characters they represent.
//
// For format_default, the possible specifiers are:
// $n n-th backreference(i.e., a copy of the n-th matched group specified with parentheses in the regex pattern).
// n must be an integer value designating a valid backreference, greater than 0, and of two digits at most.
// $& A copy of the entire match
// $` The prefix(i.e., the part of the target sequence that precedes the match).
// $' The suffix(i.e., the part of the target sequence that follows the match).
// $$ A single $ character.
//
// retain:
// If false then the replacement string completely overwrites the previous string by the replacement.
//
// Example:
// std::string s = " 14MAY 15JUNE ";
// result = string_replace(ss, regex, "$1 $2");
//
// Returns:
// std::string s = " 14 MAY 15 JUNE ";
//
// Example2:
// result = string_replace(ss, regex, "$1 $2", std::regex_constants::format_no_copy);
//
// Returns:
// std::string s = "14 MAY15 JUNE ";
//
// Example3:
// result = string_replace(ss, regex, "$1 $2", false);
//
// Returns:
// std::string s = "14 MAY15 JUNE ";
std::string string_replace(const std::string& s, const std::string& regex, const std::string& replacement,
bool retain)
{
if (retain)
return string_replace(s, regex, replacement);
else
return string_replace(s, regex, replacement, std::regex_constants::format_no_copy);
}
// Returns true if the string matches the regex.
//
// Example:
bool string_match(const std::string& s, const std::string& regex, std::regex_constants::match_flag_type flags)
{
std::smatch m;
std::regex_search(s, m, std::regex(regex), flags);
if (m.empty()) {
return false;
}
else {
return true;
}
}
// Shows all matches of the regex within the string.
//
// Example:
// show_matches("abcdef", "abc|def");
// show_matches("abc", "ab|abc"); // left Alernative matched first
//
// Match of the input against the left Alternative (a) followed by the remainder of the
// regex (c|bc) succeeds, with results:
// m[1]="a" and m[4]="bc".
// The skipped Alternatives (ab) and (c) leave their submatches
// m[3] and m[5] empty.
//
// show_matches("abc", "((a)|(ab))((c)|(bc))");
void show_matches(const std::string& s, const std::string& regex)
{
std::smatch m;
std::regex_search(s, m, std::regex(regex));
if (m.empty()) {
std::cout << "input=[" << s << "], regex=[" << regex << "]: NO MATCH\n";
}
else {
std::cout << "input=[" << s << "], regex=[" << regex << "]: ";
std::cout << "prefix=[" << m.prefix() << "] ";
for (std::size_t n = 0; n < m.size(); ++n)
std::cout << " m[" << n << "]=[" << m[n] << "] ";
std::cout << "suffix=[" << m.suffix() << "]\n";
}
}
// Splits a string into seperate tokens.
//
// Example:
// s = "0 HEAD";
// regex = "([\\d]+)[\\s]+([A-Z]*)";
std::vector string_tokenize(const std::string& s, const std::string& regex)
{
std::vector result;
std::smatch m;
std::regex_search(s, m, std::regex(regex));
if (m.empty()) {
return result;
}
else {
//result.push_back(m.prefix());
for (std::size_t n = 0; n < m.size(); ++n)
result.push_back(m[n]);
//result.push_back(m.suffix());
}
return result;
/*
std::vector result;
std::regex rgx(regex);
std::sregex_token_iterator iter(s.begin(),
s.end(),
rgx,
-1);
std::sregex_token_iterator end;
for (; iter != end; ++iter)
result.push_back(*iter);
return result;
*/
/*
std::vector result;
std::regex rgx(regex);
std::sregex_token_iterator i(s.begin(), s.end(), rgx, -1);
std::sregex_token_iterator j;
while (i != j) {
//std::cout << *i++ << " ";
result.push_back(*i++);
}
return result;
*/
}
string.h
#ifndef __SHAREWIZ_STRING_H__
#define __SHAREWIZ_STRING_H__
#include
#include
#include
// String class.
template
std::string numberToString(T pNumber);
std::vector string_find(const std::string& s, const std::string& regex);
std::string string_replace(const std::string& s, const std::string& regex, const std::string& replacement,
std::regex_constants::match_flag_type flags = std::regex_constants::match_default);
std::string string_replace(const std::string& s, const std::string& regex, const std::string& replacement,
bool retain);
bool string_match(const std::string& s, const std::string& regex,
std::regex_constants::match_flag_type flags = std::regex_constants::match_default);
void show_matches(const std::string& s, const std::string& regex);
std::vector string_tokenize(const std::string& s, const std::string& regex);
#endif
verylong.cpp
/*
#include
#include
#include
#include
#include
#include
#include
#include
*/
#include
#include
#include
#include
#include "verylong.h"
// Class Data
const Verylong Verylong::zero = Verylong("0");
const Verylong Verylong::one = Verylong("1");
const Verylong Verylong::two = Verylong("2");
// Constructors, Destructors and Conversion operators.
Verylong::Verylong(const std::string &value = "0")
{
std::string s = (value == "") ? "0" : value;
vlsign = (s[0] == '-') ? 1 : 0; // check for negative sign
if (ispunct(s[0])) // if the first character
vlstr = s.substr(1, s.length() - 1); // is a punctuation mark.
else
vlstr = s;
}
Verylong::Verylong(int n)
{
if (n < 0) // check for sign and convert the
{ // number to positive if it is negative
vlsign = 1;
n = (-n);
}
else
vlsign = 0;
if (n > 0)
while (n >= 1) // extract the number digit by digit and store
{ // internally
vlstr = char(n % 10 + '0') + vlstr;
n /= 10;
}
else
vlstr = std::string("0"); // else number is zero
}
Verylong::Verylong(const Verylong &x) : vlstr(x.vlstr), vlsign(x.vlsign)
{
}
Verylong::~Verylong()
{
}
Verylong::operator int() const
{
int number, factor = 1;
static Verylong max0(INT_MAX);
static Verylong min0(INT_MIN + 1);
std::string::const_reverse_iterator j = vlstr.rbegin();
if (*this > max0)
{
std::cerr << "Error : Conversion Verylong->integer is not possible" << std::endl;
return INT_MAX;
}
else
if (*this < min0)
{
std::cerr << "Error : Conversion Verylong->integer is not possible" << std::endl;
return INT_MIN;
}
number = *j - '0';
for (j++; j != vlstr.rend(); j++)
{
factor *= 10;
number += (*j - '0') * factor;
}
if (vlsign)
return -number;
return number;
}
Verylong::operator double() const
{
double sum, factor = 1.0;
std::string::const_reverse_iterator i = vlstr.rbegin();
sum = double(*i) - '0';
for (i++; i != vlstr.rend(); i++)
{
factor *= 10.0;
sum += double(*i - '0') * factor;
}
if (vlsign)
return -sum;
return sum;
}
Verylong::operator std::string() const
{
if (vlstr.length() == 0)
return std::string("0");
return vlstr;
}
// Various member operators
const Verylong & Verylong::operator = (const Verylong &rhs)
{
if (this == &rhs)
return *this;
vlstr = rhs.vlstr;
vlsign = rhs.vlsign;
return *this;
}
// Unary - operator
Verylong Verylong::operator -() const
{
Verylong temp(*this);
if (temp != zero)
temp.vlsign = !vlsign;
return temp;
}
// Prefix increment operator
Verylong Verylong::operator ++ ()
{
return *this = *this + one;
}
// Postfix increment operator
Verylong Verylong::operator ++ (int)
{
Verylong result(*this);
*this = *this + one;
return result;
}
// Prefix decrement operator
Verylong Verylong::operator -- ()
{
return *this = *this - one;
}
// Postfix decrement operator
Verylong Verylong::operator -- (int)
{
Verylong result(*this);
*this = *this - one;
return result;
}
Verylong Verylong::operator += (const Verylong &v)
{
return *this = *this + v;
}
Verylong Verylong::operator -= (const Verylong &v)
{
return *this = *this - v;
}
Verylong Verylong::operator *= (const Verylong &v)
{
return *this = *this * v;
}
Verylong Verylong::operator /= (const Verylong &v)
{
return *this = *this / v;
}
Verylong Verylong::operator %= (const Verylong &v)
{
return *this = *this % v;
}
Verylong Verylong::operator ^= (const Verylong °ree)
{
Verylong N(degree);
Verylong Y("1");
if (N == Verylong::zero)
return Verylong::one;
if (N < Verylong::zero)
return Verylong::zero;
while (1)
{
if (N == Verylong::zero)
{
*this = Y;
break;
}
Y = Y * *this;
N = N - Verylong::one;
}
return *this;
}
// Various friendship operators and functions.
Verylong operator + (const Verylong &u, const Verylong &v)
{
char digitsum, d1, d2, carry = 0;
std::string temp;
std::string::const_reverse_iterator j, k;
if (u.vlsign ^ v.vlsign)
{
if (u.vlsign == 0)
return u - abs(v);
else
return v - abs(u);
}
for (j = u.vlstr.rbegin(), k = v.vlstr.rbegin();
j != u.vlstr.rend() || k != v.vlstr.rend();)
{
d1 = (j == u.vlstr.rend()) ? 0 : *(j++) - '0'; // get digit
d2 = (k == v.vlstr.rend()) ? 0 : *(k++) - '0'; // get digit
digitsum = d1 + d2 + carry; // add digits
carry = (digitsum >= 10) ? 1 : 0;
digitsum -= 10 * carry;
temp = char(digitsum + '0') + temp;
}
if (carry) // if carry at end, last digit is 1
temp = '1' + temp;
if (u.vlsign)
temp = '-' + temp;
return Verylong(temp);
}
Verylong operator - (const Verylong &u, const Verylong &v)
{
char d, d1, d2, borrow = 0;
int negative;
std::string temp, temp2;
std::string::reverse_iterator i, j;
if (u.vlsign ^ v.vlsign)
{
if (u.vlsign == 0)
return u + abs(v);
else
return -(v + abs(u));
}
Verylong w, y;
if (u.vlsign == 0) // both u,v are positive
if (uc, then
{ // we have added one count too many
b = b - y;
d = d - Verylong::one;
}
quotient = quotient + d; // add to the quotient
if (i < len)
{
// partial remainder * 10 and add to next digit
c = (c - b).mult10(1);
c += Verylong(w.vlstr[w.vlstr.length() - len + i] - '0');
}
}
quotient.vlsign = u.vlsign^v.vlsign; // to determine sign
return quotient;
}
Verylong operator % (const Verylong &u, const Verylong &v)
{
return (u - v*(u / v));
}
Verylong operator ^ (const Verylong &u, const Verylong &v)
{
//return (u - v*(u / v));
Verylong temp(u);
return temp ^= v;
}
int operator == (const Verylong &u, const Verylong &v)
{
return (u.vlsign == v.vlsign && u.vlstr == v.vlstr);
}
int operator != (const Verylong &u, const Verylong &v)
{
return !(u == v);
}
int operator < (const Verylong &u, const Verylong &v)
{
if (u.vlsign < v.vlsign)
return 0;
else
if (u.vlsign > v.vlsign)
return 1;
// exclusive or (^) to determine sign
if (u.vlstr.length() < v.vlstr.length())
return (1 ^ u.vlsign);
else
if (u.vlstr.length() > v.vlstr.length())
return (0 ^ u.vlsign);
return (u.vlstr < v.vlstr && !u.vlsign) ||
(u.vlstr > v.vlstr && u.vlsign);
}
int operator <= (const Verylong &u, const Verylong &v)
{
return (u(const Verylong &u, const Verylong &v)
{
return (!(u= (const Verylong &u, const Verylong &v)
{
return (u>v || u == v);
}
// Calculate the absolute value of a number
Verylong abs(const Verylong &v)
{
Verylong u(v);
if (u.vlsign)
u.vlsign = 0;
return u;
}
// Calculate the integer square root of a number
// based on the formula (a+b)^2 = a^2 + 2ab + b^2
Verylong sqrt(const Verylong &v)
{
// if v is negative, error is reported
if (v.vlsign)
{
std::cerr << "NaN" << std::endl;
return Verylong::zero;
}
int j, k = v.vlstr.length() + 1, num = k >> 1;
Verylong y, z, sum, tempsum, digitsum;
std::string temp, w(v.vlstr);
k = 0;
j = 1;
// segment the number 2 digits by 2 digits
if (v.vlstr.length() % 2)
digitsum = Verylong(w[k++] - '0');
else
{
digitsum = Verylong((w[k] - '0') * 10 + w[k + 1] - '0');
k += 2;
}
// find the first digit of the integer square root
sum = z = Verylong(int(sqrt(double(digitsum))));
// store partial result
temp = char(int(z) + '0');
digitsum = digitsum - z*z;
for (; j::digits; // number of significant digits
if (v == Verylong::zero)
{
std::cerr << "ERROR : Division by zero" << std::endl;
return 0.0;
}
if (u == Verylong::zero)
return 0.0;
w = abs(u);
y = abs(v);
while (wc, then
{ // we have added one count too many
b -= y;
d -= 1;
}
qq += double(d); // add to the quotient
c = (c - b).mult10(1); // the partial remainder * 10
if (i < len) // and add to next digit
c += Verylong(w.vlstr[w.vlstr.length() - len + i] - '0');
}
qq *= qqscale; count = 0;
while (c != Verylong::zero && count < decno)
{
qqscale *= 0.1;
b = Verylong::zero; d = 0; // initialize b and d to 0
while (b < c)
{
b += y; d += 1;
}
if (c < b) // if b>c, then
{ // we have added one count too many
b -= y; d -= 1;
}
qq += double(d)*qqscale;
c = (c - b).mult10(1);
count++;
}
if (u.vlsign^v.vlsign) // check for the sign
qq *= (-1.0);
return qq;
}
std::ostream & operator << (std::ostream &s, const Verylong &v)
{
if (v.vlstr.length() > 0)
{
if (v.vlsign) s << "-";
s << v.vlstr;
}
else
s << "0";
return s;
}
std::istream & operator >> (std::istream &s, Verylong &v)
{
std::string temp(10000, ' ');
s >> temp;
v = Verylong(temp);
return s;
}
//
// Private member functions: multdigit(), mult10().
//
// Multiply this Verylong number by num
Verylong Verylong::multdigit(int num) const
{
int carry = 0;
std::string::const_reverse_iterator r;
if (num)
{
std::string temp;
for (r = vlstr.rbegin(); r != vlstr.rend(); r++)
{
int d1 = *r - '0', // get digit and multiplied by
digitprod = d1*num + carry; // that digit plus carry
if (digitprod >= 10) // if there's a new carry,
{
carry = digitprod / 10; // carry is high digit
digitprod -= carry * 10; // result is low digit
}
else
carry = 0; // otherwise carry is 0
temp = char(digitprod + '0') + temp; // insert char in string
}
if (carry) //if carry at end,
temp = char(carry + '0') + temp;
Verylong result(temp);
return result;
}
else
return zero;
}
// Multiply this Verylong number by 10*num
Verylong Verylong::mult10(int num) const
{
int j;
if (*this != zero)
{
std::string temp;
for (j = 0; j Verylong zero(Verylong) { return Verylong::zero; }
//template <> Verylong one(Verylong) { return Verylong::one; }
verylong.h
#ifndef __SHAREWIZ_VERYLONG_H__
#define __SHAREWIZ_VERYLONG_H__
//#include
// Very Long Integer Class
class Verylong
{
private:
// Data Fields
std::string vlstr; // The string is stored in reverse order.
int vlsign; // Sign of Verylong: +=>0; -=>1
// Private member functions
Verylong multdigit(int) const;
Verylong mult10(int) const;
public:
// Constructors and destructor
Verylong(const std::string&);
Verylong(int);
Verylong(const Verylong &);
~Verylong();
// Conversion operators
operator int() const;
operator double() const;
operator std::string () const;
// Arithmetic operators and Relational operators
const Verylong & operator = (const Verylong &); // assignment operator
Verylong operator - () const; // negate operator
Verylong operator ++ (); // prefix increment operator
Verylong operator ++ (int); // postfix increment operator
Verylong operator -- (); // prefix decrement operator
Verylong operator -- (int); // postfix decrement operator
Verylong operator += (const Verylong &);
Verylong operator -= (const Verylong &);
Verylong operator *= (const Verylong &);
Verylong operator /= (const Verylong &);
Verylong operator %= (const Verylong &);
Verylong operator ^= (const Verylong &);
friend Verylong operator + (const Verylong &, const Verylong &);
friend Verylong operator - (const Verylong &, const Verylong &);
friend Verylong operator * (const Verylong &, const Verylong &);
friend Verylong operator / (const Verylong &, const Verylong &);
friend Verylong operator % (const Verylong &, const Verylong &);
friend Verylong operator ^ (const Verylong &, const Verylong &);
friend int operator == (const Verylong &, const Verylong &);
friend int operator != (const Verylong &, const Verylong &);
friend int operator < (const Verylong &, const Verylong &);
friend int operator <= (const Verylong &, const Verylong &);
friend int operator > (const Verylong &, const Verylong &);
friend int operator >= (const Verylong &, const Verylong &);
// Other functions
friend Verylong abs(const Verylong &);
friend Verylong sqrt(const Verylong &);
friend Verylong pow(const Verylong &, const Verylong &);
friend double div(const Verylong &, const Verylong &);
// Class Data
static const Verylong zero;
static const Verylong one;
static const Verylong two;
// I/O stream functions
friend std::ostream & operator << (std::ostream &, const Verylong &);
friend std::istream & operator >> (std::istream &, Verylong &);
};
//template <> Verylong zero(Verylong) { return Verylong::zero; }
//template <> Verylong one(Verylong) { return Verylong::one; }
#endif