RBFNeuron.cpp

Go to the documentation of this file.
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 "RBFNeuron.h"
00025 #include "RBFInputData.h"
00026 
00027 namespace verve
00028 {
00029         RBFNeuron::RBFNeuron(unsigned int id)
00030         : Neuron(id)
00031         {
00032                 //mType = NEURON_TYPE_RBF;
00033                 mNumDiscreteDimensions = 0;
00034                 mNumContinuousDimensions = 0;
00035                 mDiscretePosition = NULL;
00036                 mContinuousPosition = NULL;
00037                 mRBFDenominatorInverse = 0;
00038                 mActivationThresholdDistanceSquared = 0;
00039                 mNewRBFThresholdDistanceSquared = 0;
00040         }
00041 
00042         RBFNeuron::~RBFNeuron()
00043         {
00044                 delete [] mDiscretePosition;
00045                 delete [] mContinuousPosition;
00046         }
00047 
00048         void RBFNeuron::init(real stdDevWidth, real newRBFThreshold, 
00049                 const RBFInputData& inputData)
00050         {
00051                 mNumDiscreteDimensions = inputData.numDiscInputs;
00052                 mNumContinuousDimensions = inputData.numContInputs;
00053 
00054                 if (mDiscretePosition)
00055                 {
00056                         delete [] mDiscretePosition;
00057                 }
00058 
00059                 if (0 == mNumDiscreteDimensions)
00060                 {
00061                         mDiscretePosition = NULL;
00062                 }
00063                 else
00064                 {
00065                         mDiscretePosition = new unsigned int[mNumDiscreteDimensions];
00066                         for (unsigned int i = 0; i < mNumDiscreteDimensions; ++i)
00067                         {
00068                                 mDiscretePosition[i] = inputData.discInputData[i];
00069                         }
00070                 }
00071 
00072                 if (mContinuousPosition)
00073                 {
00074                         delete [] mContinuousPosition;
00075                 }
00076 
00077                 if (0 == mNumContinuousDimensions)
00078                 {
00079                         mContinuousPosition = NULL;
00080                 }
00081                 else
00082                 {
00083                         mContinuousPosition = new real[mNumContinuousDimensions];
00084                         for (unsigned int i = 0; i < mNumContinuousDimensions; ++i)
00085                         {
00086                                 mContinuousPosition[i] = inputData.contInputData[i];
00087                         }
00088                 }
00089 
00090                 // This constant is the inverse of the denominator in the Gaussian 
00091                 // basis function.
00092                 mRBFDenominatorInverse = 1 / (2 * stdDevWidth * stdDevWidth);
00093 
00094                 // According to the 'empirical rule', 99.7% of the data are within 
00095                 // three standard deviations from the mean, so we'll 
00096                 // let the activation threshold equal (3 * stdDevWidth), giving us a 
00097                 // squared distance threshold of (3 * stdDevWidth)^2 = 
00098                 // 9 * stdDevWidth * stdDevWidth.
00099                 //mActivationThresholdDistanceSquared = 9 * stdDevWidth * stdDevWidth;
00100                 // Update: The threshold distance (3 * stdDevWidth) yielded 
00101                 // significant artifacts (e.g. as seen by visualizing the Agent's 
00102                 // value function).  Instead, we'll use (4 * stdDevWidth).
00103                 mActivationThresholdDistanceSquared = 16 * stdDevWidth * stdDevWidth;
00104 
00105                 // Store the squared distance for faster computations later.
00106                 mNewRBFThresholdDistanceSquared = newRBFThreshold * newRBFThreshold;
00107         }
00108 
00109         RBFActivationCode RBFNeuron::updateFiringRate(
00110                 const RBFInputData& inputData)
00111         {
00112                 // Check the distance between this RBF and the given point along 
00113                 // each dimension.  As soon as we can determine that the data 
00114                 // point is not close enough to affect this RBFNeuron's activation, 
00115                 // return.
00116 
00117                 // Compute the distance in discrete space.  This distance is 
00118                 // defined as zero when the values match and infinite when they 
00119                 // don't match.
00120                 for (unsigned int i = 0; i < mNumDiscreteDimensions; ++i)
00121                 {
00122                         // If the position doesn't match along every single discrete 
00123                         // dimension, quit early with no activation.
00124                         if (mDiscretePosition[i] != inputData.discInputData[i])
00125                         {
00126                                 setFiringRate(0);
00127                                 return NO_ACTIVATION;
00128                         }
00129                 }
00130 
00131                 // If we've gotten to this point, the data point must match the 
00132                 // RBF in discrete space.  For the special case when we only have 
00133                 // discrete inputs and no continuous ones, we can set the 
00134                 // activation high and quit.
00135                 if (0 == mNumContinuousDimensions)
00136                 {
00137                         setFiringRate(1);
00138                         return HIGH_ACTIVATION;
00139                 }
00140 
00141                 // Now compute the distance in continuous space by looping over 
00142                 // the continuous dimensions.
00143                 real distanceSquared = 0;
00144                 for (unsigned int i = 0; i < mNumContinuousDimensions; ++i)
00145                 {
00146                         // IDEA: If we represented RBF positions using a vector of 
00147                         // input Connections (and the input data as pre-synaptic Neuron 
00148                         // firing rates), we could delete Connections over time that 
00149                         // never get used.  This would help avoid having to compare 
00150                         // the data point to the RBF position in potentially every 
00151                         // input dimension.
00152 
00153                         // IDEA: Closely-related inputs might need to be grouped into 
00154                         // separate arrays (e.g. vision, somatosensory, etc.).  Each 
00155                         // of these arrays should have a separate set of RBFs with the 
00156                         // dimensionality of the RBF array equal to that of the 
00157                         // number of values in the particular input array.  For now, 
00158                         // assume all inputs use the same RBF array.
00159 
00160                         // The following process computes the RBFNeuron activation 
00161                         // level based on the Euclidean distance between the RBF and 
00162                         // the data point.
00163 
00164                         real distanceInThisDimension = inputData.contInputData[i] - 
00165                                 mContinuousPosition[i];
00166 
00167                         // Deal with circular input ranges, if necessary.
00168                         if (inputData.contCircularData[i])
00169                         {
00170                                 // Note that the maximum input range is 2.  If the position 
00171                                 // in the ith dimensions is more than half of this range 
00172                                 // away (i.e. 1 unit away) from the data point,  we 
00173                                 // temporarily shift the RBF position in this dimensions 
00174                                 // to make it wrap around the ends of the range.
00175 
00176                                 if (distanceInThisDimension > 1)
00177                                 {
00178                                         // Recompute distance with wrapped weight value.
00179                                         distanceInThisDimension -= 2;
00180                                 }
00181                                 else if (distanceInThisDimension < -1)
00182                                 {
00183                                         // Recompute distance with wrapped weight value.
00184                                         distanceInThisDimension += 2;
00185                                 }
00186                         }
00187 
00188                         // Add to the squared distance.
00189                         distanceSquared += 
00190                                 (distanceInThisDimension * distanceInThisDimension);
00191 
00192                         // As soon as we know the distance is beyond the activation 
00193                         // distance threshold, we can quit early and skip the remaining 
00194                         // dimensions.
00195                         if (distanceSquared > mActivationThresholdDistanceSquared)
00196                         {
00197                                 setFiringRate(0);
00198                                 return NO_ACTIVATION;
00199                         }
00200                 }
00201 
00202                 // At this point we know that the point must be close enough to the 
00203                 // RBF to affect its activation level.  We have computed the sum of 
00204                 // the squared distances along each continuous dimension.  Now 
00205                 // update the RBFNeuron's activation using a Gaussian-shaped basis 
00206                 // function.
00207                 setFiringRate(
00208                         globals::exp(-distanceSquared * mRBFDenominatorInverse));
00209 
00214                 //for (unsigned int i = 0; i < mNumContinuousDimensions; ++i)
00215                 //{
00216                 //      // Do we move the RBF in proportion to its distance from the 
00217                 //      // input point?  (RBFs with NO_ACTIVATION get ignored)...
00218                 //      real distanceInThisDimension = inputData.contInputData[i] - 
00219                 //              mContinuousPosition[i];
00220                 //      mContinuousPosition[i] += 0.01 * distanceInThisDimension;
00221 
00222                 //      //// ...or do do we move the RBF in proportion to its activation, 
00223                 //      //// which is more like 1/distance from the input point?
00224                 //      //real influence = 
00225                 //      //      globals::exp(-distanceSquared * mRBFDenominatorInverse);
00226                 //      //mContinuousPosition[i] += 0.01 * influence;
00227                 //}
00228 
00229                 if (distanceSquared > mNewRBFThresholdDistanceSquared)
00230                 {
00231                         // The point is close enough to affect the RBFNeuron's 
00232                         // activation, but far enough away to consider creating a new 
00233                         // RBF.
00234                         return LOW_ACTIVATION;
00235                 }
00236                 else
00237                 {
00238                         // The point is close enough that we won't consider creating a 
00239                         // new RBF.
00240                         return HIGH_ACTIVATION;
00241                 }
00242         }
00243 
00244         unsigned int RBFNeuron::getNumDiscreteDimensions()const
00245         {
00246                 return mNumDiscreteDimensions;
00247         }
00248 
00249         unsigned int RBFNeuron::getNumContinuousDimensions()const
00250         {
00251                 return mNumContinuousDimensions;
00252         }
00253 
00254         const unsigned int* RBFNeuron::getDiscretePosition()const
00255         {
00256                 return mDiscretePosition;
00257         }
00258 
00259         const real* RBFNeuron::getContinuousPosition()const
00260         {
00261                 return mContinuousPosition;
00262         }
00263 }

Generated on Tue Jan 24 21:46:37 2006 for Verve by  doxygen 1.4.6-NO