Package eas.simulation.brain.neural

Source Code of eas.simulation.brain.neural.Neuron

/*
* File name:        Neuron.java (package eas.simulation.brain.neural)
* Author(s):        Lukas König
* Java version:     6.0
* Generation date:  29.07.2011 (15:04:04)
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
*   author or licensor (but not in any way that suggests that they endorse
*   you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
*   distribute the resulting work only under the same or a similar license to
*   this one.
*
* + Detailed license conditions (Germany):
*   http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
*   http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/

package eas.simulation.brain.neural;

import java.awt.image.BufferedImage;
import java.io.Serializable;
import java.util.LinkedList;

import eas.math.geometry.Vector2D;
import eas.simulation.brain.neural.functions.ActivationFunction;
import eas.simulation.brain.neural.functions.ActivationFunctionConstant;
import eas.simulation.brain.neural.functions.TransitionFunction;
import eas.simulation.brain.neural.functions.TransitionFunctionWeightedSum;

/**
* @author Lukas König
*
*/
public class Neuron implements Serializable {

    private static final long serialVersionUID = 224664994130046667L;
    public static final int INPUT_NEURON = 0;
    public static final int HIDDEN_NEURON = 1;
    public static final int OUTPUT_NEURON = 2;
    public static final int INPUT_OUTPUT_NEURON = 3;
   
    private int nrnType;
   
    public void setPaintBlueBorder(boolean paintBlueBorder) {
        this.getActFct().setPaintBlueBorder(paintBlueBorder);
    }
   
    /**
     * The neuron's activation function. Activation functions are constrained
     * to return values from [0, 1]. [TODO: ???]
     */
    private ActivationFunction actFct;
   
    /**
     * The neuron's transition function - standard: weighted sum.
     */
    private TransitionFunction trnFct;

    private int id;

    /**
     * The output generated by the neuron as input for the next neurons
     * (or in backwards mode for the previous neurons).
     */
    private double netOutput = 0.0;

    /**
     * Only available for input neurons.
     */
    private double input = 0.0;
   
    /**
     * Only available for output neurons.
     */
    private double output = 0.0;

    /**
     * List of all incoming links. Kept fresh all the time.
     */
    private LinkedList<NeuralLink> incomingLinks;
   
//    /**
//     * List of all outgoing links. Only needed in backward mode and NOT
//     * refreshed automatically. Use calculateOutgoingLinks() to refresh this
//     * list.
//     */
//    private LinkedList<NeuralLink> outgoingLinks = null;
   
    private GeneralNeuralNetwork network;
   
    /**
     * Constructs a new Neuron with standard transition function, i.e.,
     * weighted sum.
     *
     * @param activFct  The activation function.
     */
    protected Neuron(int neuronID, ActivationFunction activFct, int neuronType, GeneralNeuralNetwork net) {
        this(neuronID, activFct, new TransitionFunctionWeightedSum(), neuronType, net);
    }
   
    public Neuron(int neuronID, ActivationFunction activFct, TransitionFunction transFct, int neuronType, GeneralNeuralNetwork net) {
        this.actFct = activFct;
        this.trnFct = transFct;
        this.nrnType = neuronType;
        this.id = neuronID;
        this.network = net;
        this.incomingLinks = new LinkedList<NeuralLink>();
    }
   
    private boolean forwardMode = true;
   
    /**
     * Sets the forward mode and resets the net output to value.
     *
     * @param forwardMode  The forward mode.
     * @param value  The value to set to.
     */
    public void setForwardModeAndResetNetOutput(double value, boolean forwardMode) {
        this.forwardMode = forwardMode;
        this.netOutput = value;
    }
   
    public void computeAndStoreNetOutput() {
        if (!forwardMode) {
            throw new RuntimeException("Neuron is not in forward mode, no forward calculations allowed.");
        }
       
        LinkedList<Vector2D> inputSignals = new LinkedList<Vector2D>();
       
        if (this.isInput()) {
            inputSignals.add(new Vector2D(input, 1));
        }
       
        for (NeuralLink link : incomingLinks) {
            Vector2D tuple = new Vector2D(
                    this.network.getNeuron(link.getSourceNeuronID()).netOutput,
                    link.getWeight());
            inputSignals.add(tuple);
        }
       
        double netInput = this.trnFct.inputSigma(inputSignals);
        double netOutput = this.actFct.activationPhi(netInput);
        this.netOutput = netOutput;
    }
   
//    /**
//     * Note that the NeuralLink is used in reverse here, meaning that the
//     * stored "sourceID" is in fact the target ID (source in the backwards
//     * sense).
//     *
//     * @return
//     */
//    public LinkedList<NeuralLink> calculateOutgoingLinks() {
//        if (this.forwardMode) {
//            this.network.getPars().logWarning("Why do you need an outgoing link in forward mode?");
//        }
//       
//        this.outgoingLinks = new LinkedList<NeuralLink>();
//       
//        HashMap<Integer, Neuron> neurons = this.network.getNeurons();
//       
//        for (Neuron n : neurons.values()) {
//            LinkedList<NeuralLink> incomingForN = n.incomingLinks;
//            for (NeuralLink link : incomingForN) {
//                if (link.getSourceNeuronID() == this.getId()) {
//                    outgoingLinks.add(new NeuralLink(n.getId(), link.getWeight()));
//                }
//            }
//        }
//       
//        return outgoingLinks;
//    }
   
//    /**
//     * This is the inverse method to computeAndStoreNetOutput(). It calculates
//     * based on the backwards incoming (or better outgoing) values of the
//     * outgoing links the net input for the former neurons with ids smaller than
//     * this.getId(). This input is stored in this.output meaning that
//     * the neuron can only be used in one mode at a time and the two methods
//     * should not be mixed!
//     */
//    public void computeAndStoreInverseNetOutput() {
//        if (forwardMode) {
//            throw new RuntimeException("Neuron is in forward mode, no backward calculations allowed.");
//        }
//       
//        this.calculateOutgoingLinks();
//       
//        LinkedList<Vector2D> outputSignals = new LinkedList<Vector2D>();
//       
//        if (this.isOutput()) {
//            outputSignals.add(new Vector2D(output, 1));
//        }
//       
//        for (NeuralLink link : outgoingLinks) {
//            Vector2D tuple = new Vector2D(
//                    this.network.getNeuron(link.getSourceNeuronID()).getNetOutput(),
//                    link.getWeight());
//           
//           
//           
//            outputSignals.add(tuple);
//        }
//       
//        double netInput = this.trnFct.inputSigma(outputSignals);
//        double netOutput = this.actFct.activationPhi(netInput);
//        this.netOutput = netOutput;
//    }
   
    public boolean isInput() {
        return this.nrnType == INPUT_NEURON || this.nrnType == INPUT_OUTPUT_NEURON;
    }
   
    public boolean isHidden() {
        return this.nrnType == HIDDEN_NEURON;
    }
   
    public boolean isOutput() {
        return this.nrnType == OUTPUT_NEURON || this.nrnType == INPUT_OUTPUT_NEURON;
    }
   
    /**
     * @return Returns the id.
     */
    public int getId() {
        return this.id;
    }

    /**
     * Inserts a new incoming link if no link from the according source neuron
     * existed before. If it did, the weight is changed to the new link's
     * weight.
     *
     * @param link  The link to add.
     */
    public void addIncomingLink(NeuralLink link) {
        NeuralLink alreadyThere = this.containsLink(link.getSourceNeuronID());
       
        if (alreadyThere != null) {
            alreadyThere.setWeight(link.getWeight());
        } else {
            this.incomingLinks.add(link);
        }
    }
   
    public boolean removeIncomingLink(int fromNeuronID) {
        for (NeuralLink link : this.incomingLinks) {
            if (link.getSourceNeuronID() == fromNeuronID) {
                this.incomingLinks.remove(link);
                return true;
            }
        }
       
        return false;
    }
   
    /**
     * @param sourceID  The id of the source node.
     *
     * @return  The Link associated to the source node if one exists,
     *          <code>null</code> otherwise.
     */
    public NeuralLink containsLink(int sourceID) {
        for (NeuralLink link : this.incomingLinks) {
            if (link.getSourceNeuronID() == sourceID) {
                return link;
            }
        }
       
        return null;
    }
   
    public void setTransitionFunctionSigma(final TransitionFunction sigma) {
        this.trnFct = sigma;
    }
   
    public void setActivationFunctionPhi(final ActivationFunction phi) {
        this.actFct = phi;
    }
   
    public BufferedImage generateNeuronView(int width, int height) {
        return this.actFct.getFunctionView(width, height);
    }

    public LinkedList<NeuralLink> getIncomingLinks() {
        return this.incomingLinks;
    }

    /**
     * @return Returns the output. The net output is calculated temporarily
     *         to its theoretical future value and set back internally afterwards.
     *         The values of the other neurons are left untouched.
     */
    public double getNetOutput() {
        double netOutputOld = this.netOutput;
        this.computeAndStoreNetOutput();
        double netOutput = this.netOutput;
        this.netOutput = netOutputOld;
        return netOutput;
    }

    /**
     * Sets the net output to a new value. Do this only if you know what you're
     * doing - at least from outside this class.
     *
     * @param setToValue
     */
    protected void setNetOutput(double setToValue) {
        this.netOutput = setToValue;
    }
   
    public double getInput() {
        if (!this.isInput()) {
            throw new RuntimeException("The neuron has no input as it is not an input neuron.");
        }
        return this.input;
    }

    public void setInput(double input) {
        if (!this.isInput()) {
            throw new RuntimeException("The neuron has no input as it is not an input neuron.");
        }
        this.input = input;
    }
   
    public double getOutput() {
        if (!this.isOutput()) {
            throw new RuntimeException("The neuron has no output as it is not an output neuron.");
        }
        return this.output;
    }
   
    public void setOutput(double output) {
        if (!this.isOutput()) {
            throw new RuntimeException("The neuron has no output as it is not an output neuron.");
        }
        this.output = output;
    }
   
    public void setId(int id) {
        this.id = id;
    }
   
    @Override
    public String toString() {
        String inOut = "";
        inOut += "(";
        try {inOut += this.getInput();} catch (Exception e) {inOut += "X";}
        inOut += " -> ";
        try {inOut += this.getNetOutput();} catch (Exception e) {inOut += "X";}
        inOut += ")";
       
        String s = "Neuron " + this.getId() + ": " + inOut;
        return s;
    }
   
    public static Neuron getDummyNeuron() {
        return new Neuron(0, new ActivationFunctionConstant(0), Neuron.HIDDEN_NEURON, null) {
            /**
             *
             */
            private static final long serialVersionUID = 1256051857833946920L;

            @Override
            public BufferedImage generateNeuronView(int width, int height) {
                return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
            }
        };
    }

    /**
     * Resets input, output and netOutput to 0;
     */
    protected void reset() {
        this.input = 0;
        this.output = 0;
        this.netOutput = 0;
    }
   
    /**
     * Two neurons are equal if they have the same incoming links and the same
     * transition and activation functions as well as neuron type (hidden,
     * input or output). Note that the current states of the neurons are not
     * compared (i.e., their current input, output and net output values).
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((this.actFct == null) ? 0 : this.actFct.hashCode());
        result = prime * result + this.id;
        result = prime
                * result
                + ((this.incomingLinks == null) ? 0 : this.incomingLinks
                        .hashCode());
        result = prime * result + this.nrnType;
        result = prime * result
                + ((this.trnFct == null) ? 0 : this.trnFct.hashCode());
        return result;
    }

    /**
     * Two neurons are equal if they have the same incoming links and the same
     * transition and activation functions as well as neuron type (hidden,
     * input or output). Note that the current states of the neurons are not
     * compared (i.e., their current input and output values).
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Neuron other = (Neuron) obj;
        if (this.actFct == null) {
            if (other.actFct != null)
                return false;
        } else if (!this.actFct.equals(other.actFct))
            return false;
        if (this.id != other.id)
            return false;
        if (this.incomingLinks == null) {
            if (other.incomingLinks != null)
                return false;
        } else if (!this.incomingLinks.equals(other.incomingLinks))
            return false;
        if (this.nrnType != other.nrnType)
            return false;
        if (this.trnFct == null) {
            if (other.trnFct != null)
                return false;
        } else if (!this.trnFct.equals(other.trnFct))
            return false;
        return true;
    }
   
    public ActivationFunction getActFct() {
        return this.actFct;
    }
}
TOP

Related Classes of eas.simulation.brain.neural.Neuron

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.