neuron.cpp

#include <iostream>
#include <cassert>
 
#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<Connection>& 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<connections_in.size(); i++)
	{
		if (!connections_in[i])
			continue;
 
		std::cout << "  Connection-In[" << i << "] w=" << connections_in[i]->getWeight() << ", d=" << connections_in[i]->getDeltaWeight() << std::endl;
	}
 
	for (unsigned int i = 0; i<connections_out.size(); i++)
	{
		if (!connections_out[i])
			continue;
 
		std::cout << "  Connection-Out[" << i << "] w=" << connections_out[i]->getWeight() << ", d=" << connections_out[i]->getDeltaWeight() << std::endl;
	}
}