package ac.essex.gp.neural;

import java.util.ArrayList;

/**
 * Neurons are arranged in layers. Each neuron may be connected to every other neuron on its
 * layer.
 *
 * @author Olly Oechsle, University of Essex, Date: 06-Mar-2007
 * @version 1.0
 */
public class Neuron {

    public static final double LearningRate = 0.5;

    protected NeuronLayer l;

    protected ArrayList<Connection> backwardConnections;
    protected ArrayList<Connection> forwardConnections;

    double input = 0;
    double output = 0;
    double bias = 1;

    double deltaValue;
    double errorFactor;

    public Neuron(NeuronLayer l) {
        backwardConnections = new ArrayList<Connection>(l.size);
        forwardConnections = new ArrayList<Connection>(l.size);
        this.l = l;
    }

    public void connectTo(Neuron other) {
        Connection c = new Connection(this, other);
        this.forwardConnections.add(c);
        other.backwardConnections.add(c);
    }

    public void setOutput(double output) {
        this.output = output;
    }

    public double updateOutput() {

        // Part 1 - Summation
        double netValue = 0;
        // add together the inputLayer from the incoming neurons
        for (Connection c : backwardConnections) {
            netValue += c.from.getOutputValue() * c.weight;
        }
        netValue = netValue + bias;

        // Part 2 - Activation (using the Sigmoid Transfer Function)
        output = 1 / (1 + Math.exp(-netValue));

        return output;
    }

    public double getOutputValue() {
        return output;
    }

    public void setDeltaValue(double delta) {
        this.deltaValue = delta;
    }

    public void updateFreeParams() {
        // update bias
        bias += LearningRate * 1 * deltaValue;
        // update weights
        for (Connection conn : backwardConnections) {
            conn.weight = conn.weight + LearningRate * output * deltaValue;
        }
    }

}
