00001 /************************************************************************ 00002 * Verve * 00003 * Copyright (C) 2004-2006 * 00004 * Tyler Streeter tylerstreeter@gmail.com * 00005 * All rights reserved. * 00006 * Web: http://verve-agents.sourceforge.net * 00007 * * 00008 * This library is free software; you can redistribute it and/or * 00009 * modify it under the terms of EITHER: * 00010 * (1) The GNU Lesser General Public License as published by the Free * 00011 * Software Foundation; either version 2.1 of the License, or (at * 00012 * your option) any later version. The text of the GNU Lesser * 00013 * General Public License is included with this library in the * 00014 * file license-LGPL.txt. * 00015 * (2) The BSD-style license that is included with this library in * 00016 * the file license-BSD.txt. * 00017 * * 00018 * This library is distributed in the hope that it will be useful, * 00019 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * 00021 * license-LGPL.txt and license-BSD.txt for more details. * 00022 ************************************************************************/ 00023 00024 #include "Neuron.h" 00025 #include "Connection.h" 00026 00027 namespace verve 00028 { 00029 Neuron::Neuron(unsigned int id) 00030 { 00031 mID = id; 00032 mFiringRate = 0; 00033 mSynapticInputSum = 0; 00034 } 00035 00036 Neuron::~Neuron() 00037 { 00038 } 00039 00040 void Neuron::resetShortTermMemory() 00041 { 00042 mFiringRate = 0; 00043 mSynapticInputSum = 0; 00044 } 00045 00046 void Neuron::normalizeInputWeights() 00047 { 00048 unsigned int numDendrites = (unsigned int)mDendrites.size(); 00049 if (numDendrites < 2) 00050 { 00051 return; 00052 } 00053 00056 00058 //real maxMagnitude = 0; 00059 00060 //std::vector<Connection*>::iterator iter; 00061 //for (iter = mDendrites.begin(); iter != mDendrites.end(); ++iter) 00062 //{ 00063 // if (globals::abs((*iter)->getWeight()) > maxMagnitude) 00064 // { 00065 // maxMagnitude = globals::abs((*iter)->getWeight()); 00066 // } 00067 //} 00068 00075 //if (maxMagnitude > 1) 00076 //{ 00077 // real inverseMagnitude = 1 / maxMagnitude; 00078 00079 // for (iter = mDendrites.begin(); iter != mDendrites.end(); ++iter) 00080 // { 00081 // real weight = (*iter)->getWeight(); 00082 // //real newWeightMagnitude = globals::scaleZeroToOne( 00083 // // globals::abs(weight), 0, maxMagnitude); 00084 // real newWeightMagnitude = globals::abs(weight) * 00085 // inverseMagnitude; 00086 00087 // if (weight < 0) 00088 // { 00089 // (*iter)->setWeight(-newWeightMagnitude); 00090 // } 00091 // else 00092 // { 00093 // (*iter)->setWeight(newWeightMagnitude); 00094 // } 00095 // } 00096 //} 00097 00098 // METHOD 2: Scale weights to keep the sum of squared weights equal 00099 // to 1 (i.e. a unit circle). 00100 00101 // Find the sum of squared weights. 00102 real sumOfSquaredWeights = 0; 00103 00104 for (unsigned int i = 0; i < numDendrites; ++i) 00105 { 00106 real weight = mDendrites[i]->getWeight(); 00107 sumOfSquaredWeights += (weight * weight); 00108 } 00109 00110 // Don't do anything if the sum is zero (in which case the weights 00111 // are still all zero). 00112 if (sumOfSquaredWeights > 0) 00113 { 00114 // Precompute the inverse of the square root of the sum. 00115 real invRootSum = 1 / globals::sqrt(sumOfSquaredWeights); 00116 00117 // Scale the weights. After this loop the sum of squared 00118 // weights should be 1. 00119 for (unsigned int i = 0; i < numDendrites; ++i) 00120 { 00121 mDendrites[i]->setWeight(mDendrites[i]->getWeight() * 00122 invRootSum); 00123 } 00124 } 00125 } 00126 00127 void Neuron::setFiringRate(real value) 00128 { 00129 // If nothing has changed, quit early to save time. 00130 if (value == mFiringRate) 00131 { 00132 return; 00133 } 00134 00135 real deltaFiringRate = value - mFiringRate; 00136 mFiringRate = value; 00137 00138 // Update post-synaptic Neurons' synaptic input sums. 00139 unsigned int size = (unsigned int)mAxons.size(); 00140 for (unsigned int i = 0; i < size; ++i) 00141 { 00142 mAxons[i]->getPostNeuron()->addToSynapticInputSum( 00143 deltaFiringRate * mAxons[i]->getWeight()); 00144 } 00145 } 00146 00147 void Neuron::addToSynapticInputSum(real delta) 00148 { 00149 mSynapticInputSum += delta; 00150 } 00151 00152 void Neuron::updateFiringRateLinear() 00153 { 00154 // IDEA: it might speed things up to keep track of whether the 00155 // input sum has changed, then only update things if it has. 00156 // The Neuron::setFiringRate should at least avoid updating 00157 // post-synaptic input sums when the firing rate hasn't changed. 00158 00159 // Just use the linear function firing rate = input sum. 00160 setFiringRate(mSynapticInputSum); 00161 } 00162 00163 void Neuron::updateFiringRateLinearBoundedNegOneToOne() 00164 { 00165 // IDEA: it might speed things up to keep track of whether the 00166 // input sum has changed, then only update things if it has. 00167 // The Neuron::setFiringRate should at least avoid updating 00168 // post-synaptic input sums when the firing rate hasn't changed. 00169 00170 // Just use the linear function firing rate = input sum. 00171 if (mSynapticInputSum < -1) 00172 { 00173 setFiringRate(-1); 00174 } 00175 else if (mSynapticInputSum > 1) 00176 { 00177 setFiringRate(1); 00178 } 00179 else 00180 { 00181 setFiringRate(mSynapticInputSum); 00182 } 00183 } 00184 00185 void Neuron::updateFiringRateLinearBoundedZeroToOne() 00186 { 00187 // IDEA: it might speed things up to keep track of whether the 00188 // input sum has changed, then only update things if it has. 00189 // The Neuron::setFiringRate should at least avoid updating 00190 // post-synaptic input sums when the firing rate hasn't changed. 00191 00192 // Just use the linear function firing rate = input sum. 00193 if (mSynapticInputSum < 0) 00194 { 00195 setFiringRate(0); 00196 } 00197 else if (mSynapticInputSum > 1) 00198 { 00199 setFiringRate(1); 00200 } 00201 else 00202 { 00203 setFiringRate(mSynapticInputSum); 00204 } 00205 } 00206 00207 void Neuron::updateFiringRateSigmoid() 00208 { 00209 // IDEA: it might speed things up to keep track of whether the 00210 // input sum has changed, then only update things if it has. 00211 // The Neuron::setFiringRate should at least avoid updating 00212 // post-synaptic input sums when the firing rate hasn't changed. 00213 00214 // Sigmoid function. Avoid overflow. 00215 if (mSynapticInputSum < -500) 00216 { 00217 setFiringRate(0); 00218 } 00219 else if (mSynapticInputSum > 500) 00220 { 00221 setFiringRate(1); 00222 } 00223 else 00224 { 00225 setFiringRate(1 / (1 + globals::exp(-mSynapticInputSum))); 00226 } 00227 } 00228 00229 real Neuron::getFiringRate()const 00230 { 00231 return mFiringRate; 00232 } 00233 00234 void Neuron::addDendrite(Connection* c) 00235 { 00236 mDendrites.push_back(c); 00237 } 00238 00239 unsigned int Neuron::getNumDendrites()const 00240 { 00241 return (unsigned int)mDendrites.size(); 00242 } 00243 00244 Connection* Neuron::getDendrite(unsigned int i) 00245 { 00246 return mDendrites.at(i); 00247 } 00248 00249 void Neuron::addAxon(Connection* c) 00250 { 00251 mAxons.push_back(c); 00252 } 00253 00254 unsigned int Neuron::getNumAxons()const 00255 { 00256 return (unsigned int)mAxons.size(); 00257 } 00258 00259 Connection* Neuron::getAxon(unsigned int i) 00260 { 00261 return mAxons.at(i); 00262 } 00263 00264 int Neuron::getID()const 00265 { 00266 return mID; 00267 } 00268 }