summaryrefslogtreecommitdiff
path: root/2015-spacebot/src/brain
diff options
context:
space:
mode:
Diffstat (limited to '2015-spacebot/src/brain')
-rw-r--r--2015-spacebot/src/brain/neural_link.cpp11
-rw-r--r--2015-spacebot/src/brain/neural_network.cpp163
-rw-r--r--2015-spacebot/src/brain/neuron.cpp40
3 files changed, 214 insertions, 0 deletions
diff --git a/2015-spacebot/src/brain/neural_link.cpp b/2015-spacebot/src/brain/neural_link.cpp
new file mode 100644
index 0000000..6997bd6
--- /dev/null
+++ b/2015-spacebot/src/brain/neural_link.cpp
@@ -0,0 +1,11 @@
+#include "brain/neural_link.h"
+
+NeuralLink::NeuralLink(NeuralNode* input, double weight)
+ :_input(input), _weight(weight)
+{
+}
+
+double NeuralLink::weightedActivation() const
+{
+ return _input->activation()*_weight;
+}
diff --git a/2015-spacebot/src/brain/neural_network.cpp b/2015-spacebot/src/brain/neural_network.cpp
new file mode 100644
index 0000000..c8177e8
--- /dev/null
+++ b/2015-spacebot/src/brain/neural_network.cpp
@@ -0,0 +1,163 @@
+#include "brain/neural_network.h"
+#include "brain/neuron.h"
+#include <limits>
+
+NeuralNetwork::NeuralNetwork(std::istream &&networkConfigFile, unsigned int numberOfSensors, unsigned int numberOfOutputs)
+{
+ _neurons.reserve(400);
+ _sensors.reserve(numberOfSensors);
+ _outputs.reserve(numberOfOutputs);
+
+ _biasNode = std::make_shared<BiasNode>();
+
+ for (unsigned int i=0; i<numberOfSensors; ++i)
+ {
+ auto sensor = std::make_shared<Sensor>(i);
+ _sensors.push_back(sensor);
+ }
+ for (unsigned int i=0; i<numberOfOutputs; ++i)
+ {
+ auto output = findOrAddNeuron(i);
+ _outputs.push_back(output);
+ }
+
+ parseFile(std::move(networkConfigFile));
+}
+
+NeuralNetwork::NeuralNetwork(std::istream &&networkConfigFile, std::vector<bool> sensorInitialValues, unsigned int numberOfOutputs)
+{
+ _neurons.reserve(400);
+ _sensors.reserve(sensorInitialValues.size());
+ _outputs.reserve(numberOfOutputs);
+
+ _biasNode = std::make_shared<BiasNode>();
+
+ for (unsigned int i=0; i<sensorInitialValues.size(); ++i)
+ {
+ auto sensor = std::make_shared<Sensor>(i);
+ sensor->setActivation(sensorInitialValues[i] ? 1 : 0);
+ _sensors.push_back(sensor);
+ }
+ for (unsigned int i=0; i<numberOfOutputs; ++i)
+ {
+ auto output = findOrAddNeuron(i);
+ _outputs.push_back(output);
+ }
+
+ parseFile(std::move(networkConfigFile));
+}
+
+void NeuralNetwork::parseFile(std::istream &&file)
+{
+ double weight;
+ char srcType;
+ unsigned int srcId;
+ unsigned int destId;
+
+ while (file.get(srcType) &&
+ file >> srcId &&
+ file.ignore(std::numeric_limits<std::streamsize>::max(), 'n') &&
+ file >> destId &&
+ file >> weight &&
+ file.ignore(std::numeric_limits<std::streamsize>::max(), '\n'))
+ {
+ std::shared_ptr<NeuralNode> source;
+ std::shared_ptr<Neuron> destination;
+ switch (srcType)
+ {
+ case 's':
+ source = findOrAddSensor(srcId);
+ break;
+ case 'b':
+ source = _biasNode;
+ break;
+ default:
+ source = findOrAddNeuron(srcId);
+ }
+ destination = findOrAddNeuron(destId);
+
+ addLink(source, destination, weight);
+ }
+
+}
+
+void NeuralNetwork::addLink(std::shared_ptr<NeuralNode> source, std::shared_ptr<Neuron> destination, double weight)
+{
+ NeuralLink link(source.get(), weight);
+ destination->addInput(std::move(link));
+}
+
+std::shared_ptr<Sensor> NeuralNetwork::findOrAddSensor(unsigned int id)
+{
+ while (_sensors.size() <= id)
+ {
+ auto sensor = std::make_shared<Sensor>(_sensors.size());
+ _sensors.push_back(sensor);
+ }
+
+ return _sensors.at(id);
+}
+
+std::shared_ptr<Neuron> NeuralNetwork::findOrAddNeuron(unsigned int id)
+{
+ while (_neurons.size() <= id)
+ {
+ auto neuron = std::make_shared<Neuron>(_neurons.size());
+ _neurons.push_back(neuron);
+ }
+
+ return _neurons.at(id);
+}
+
+void NeuralNetwork::setInput(unsigned int inputIndex, double activation)
+{
+ _sensors.at(inputIndex)->setActivation(activation);
+}
+
+unsigned int NeuralNetwork::findMaxOutputIndex() const
+{
+ bool anyNodeChanged = true;
+ auto maxIterations = _neurons.size()*10;
+ for (unsigned int iteration=0; anyNodeChanged && iteration<maxIterations; ++iteration)
+ {
+ anyNodeChanged = false;
+ for (auto const& neuron : _neurons)
+ {
+ bool activationChanged = neuron->calculateActivation();
+ anyNodeChanged = anyNodeChanged || activationChanged;
+ }
+ }
+
+ int currentMaxIndex = 0;
+ double currentMaxActivation = _outputs.at(0)->activation();
+
+ for (unsigned int i=1; i<_outputs.size(); ++i)
+ {
+ double activation = _outputs.at(i)->activation();
+ if (activation >= currentMaxActivation)
+ {
+ currentMaxActivation = activation;
+ currentMaxIndex = i;
+ }
+ }
+ return currentMaxIndex;
+}
+
+bool NeuralNetwork::linkExists(std::string srcIdentifier, std::string destIdentifier, double weight) const
+{
+ std::shared_ptr<Neuron> dest;
+
+ for (auto const& node : _neurons)
+ {
+ if (node->identifier() == destIdentifier)
+ {
+ dest = node;
+ }
+ }
+
+ if (!dest)
+ {
+ return false;
+ }
+ return dest->hasInputWithWeight(srcIdentifier, weight);
+}
diff --git a/2015-spacebot/src/brain/neuron.cpp b/2015-spacebot/src/brain/neuron.cpp
new file mode 100644
index 0000000..c7dba2c
--- /dev/null
+++ b/2015-spacebot/src/brain/neuron.cpp
@@ -0,0 +1,40 @@
+#include "brain/neuron.h"
+#include <cmath>
+
+double Neuron::sigmoid(double input) const
+{
+ const double slope = 4.924273;
+ return (1/(1+(std::exp(-(slope*input)))));
+}
+
+bool Neuron::calculateActivation()
+{
+ double newActivation = 0;
+ for (auto const& link : _inputLinks)
+ {
+ newActivation += link.weightedActivation();
+ }
+ newActivation = sigmoid(newActivation);
+
+ const double errorMargin = 0.000001;
+ bool activationChanged = std::abs(newActivation - _activation) > errorMargin;
+ _activation = newActivation;
+ return activationChanged;
+}
+
+void Neuron::addInput(NeuralLink&& link)
+{
+ _inputLinks.push_back(std::move(link));
+}
+
+bool Neuron::hasInputWithWeight(std::string srcIdentifier, double weight) const
+{
+ for (auto const& link : _inputLinks)
+ {
+ if (link.inputIdentifier() == srcIdentifier && link.weight() == weight)
+ {
+ return true;
+ }
+ }
+ return false;
+}