RBFPopulation.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 "RBFPopulation.h"
00025 #include "RBFNeuron.h"
00026 #include "Projection.h"
00027 #include "RBFInputData.h"
00028 
00029 namespace verve
00030 {
00031         RBFPopulation::RBFPopulation()
00032         : Population()
00033         {
00034                 mContinuousResolution = 0;
00035                 mNumDiscreteDimensions = 0;
00036                 mNumContinuousDimensions = 0;
00037                 mIsDynamic = true;
00038                 mSingleState = false;
00039                 mStdDevWidth = 0;
00040         }
00041 
00042         RBFPopulation::~RBFPopulation()
00043         {
00044         }
00045 
00046         void RBFPopulation::init(const RBFInputData& inputData, bool isDynamic)
00047         {
00048                 assert(inputData.contResolution > 0);
00049 
00050                 clear();
00051 
00052                 mContinuousResolution = inputData.contResolution;
00053                 mNumDiscreteDimensions = inputData.numDiscInputs;
00054                 mNumContinuousDimensions = inputData.numContInputs;
00055                 mIsDynamic = isDynamic;
00056 
00057                 // The RBF std. dev. width equals the distance of one standard 
00058                 // deviation from the RBF center.  This value affects the width 
00059                 // of each RBF's Gaussian curve (and, thus, how much the RBFs 
00060                 // will overlap).  
00061 
00062                 // RBF WIDTH METHOD 1: Make the RBF width depend on the resolution 
00063                 // (and distance between neighboring RBFs).  We'll set it equal 
00064                 // to the distance between neighboring RBFs.
00065                 mStdDevWidth = 2 / (real)mContinuousResolution;
00066 
00067                 // RBF WIDTH METHOD 2: Use a constant width that is independent 
00068                 // of the resolution.  We'll set it to a fraction of the input 
00069                 // range (which is 2).
00070                 //mStdDevWidth = (real)0.5;
00071 
00072                 // Check if this is a "null" Population with a single, constantly-
00073                 // active Neuron.
00074                 if (0 == mNumDiscreteDimensions && 0 == mNumContinuousDimensions)
00075                 {
00076                         mSingleState = true;
00077 
00078                         // Just create a single RBF to represent the one possible 
00079                         // "state."
00080                         Population::init(1);
00081 
00082                         // Keep the single RBFNeuron active constantly.
00083                         mNeurons[0]->setFiringRate(1);
00084 
00085                         return;
00086                 }
00087 
00088                 // Check if this is a non-dynamic RBFPopulation.  If so, create 
00089                 // an RBF for every position in the input space.
00090                 if (!isDynamic)
00091                 {
00092                         RBFInputData tempInputData;
00093                         tempInputData.init(inputData.numDiscInputs, 
00094                                 inputData.discNumOptionsData, inputData.discInputData, 
00095                                 inputData.numContInputs, inputData.contResolution, 
00096                                 inputData.contCircularData, inputData.contInputData);
00097                         unsigned numStates = tempInputData.computeNumUniqueStates(
00098                                 inputData.contResolution);
00099                         for (unsigned int i = 0; i < numStates; ++i)
00100                         {
00101                                 tempInputData.setToUniqueState(i, numStates, 
00102                                         inputData.contResolution);
00103                                 makeNewRBF(tempInputData);
00104                         }
00105                 }
00106 
00107                 // If we're using a dynamic RBFPopulation, we don't need to create 
00108                 // any RBFNeurons at this point.  They'll get created dynamically 
00109                 // later.
00110         }
00111 
00112         void RBFPopulation::resetShortTermMemory()
00113         {
00114                 Population::resetShortTermMemory();
00115 
00116                 // Empty the lists of active Neurons.
00117                 mActiveNeurons.clear();
00118 
00119                 if (mSingleState)
00120                 {
00121                         // Keep the single RBFNeuron active constantly.
00122                         mNeurons[0]->setFiringRate(1);
00123                 }
00124         }
00125 
00126         void RBFPopulation::clear()
00127         {
00128                 Population::clear();
00129         }
00130 
00131         void RBFPopulation::updateFiringRatesRBF(const RBFInputData& inputData, 
00132                 bool allowDynamicRBFCreation)
00133         {
00134                 mActiveNeurons.clear();
00135 
00136                 if (mSingleState)
00137                 {
00138                         // This is basically a null Population with a single, 
00139                         // constantly-active Neuron.
00140 
00141                         // Track the active Neuron.
00142                         mActiveNeurons.push_back(mNeurons.back());
00143                         return;
00144                 }
00145 
00146                 // Assume we need to make a new RBF until we find an existing 
00147                 // one with high activation.
00148                 bool needNewRBF = true;
00149 
00150                 unsigned int numRBFs = (unsigned int)mNeurons.size();
00151                 for (unsigned int i = 0; i < numRBFs; ++i)
00152                 {
00153                         RBFNeuron* neuron = static_cast<RBFNeuron*>(mNeurons[i]);
00154                         RBFActivationCode code = neuron->updateFiringRate(inputData);
00155 
00156                         if (HIGH_ACTIVATION == code)
00157                         {
00158                                 needNewRBF = false;
00159 
00160                                 // Track the active Neuron.
00161                                 mActiveNeurons.push_back(neuron);
00162                         }
00163                         else if (LOW_ACTIVATION == code)
00164                         {
00165                                 // Track the active Neuron.
00166                                 mActiveNeurons.push_back(neuron);
00167                         }
00168                 }
00169 
00170                 if (allowDynamicRBFCreation && mIsDynamic && needNewRBF)
00171                 {
00172                         makeNewRBF(inputData);
00173                         Neuron* newRBFNeuron = mNeurons.back();
00174                         connectNewRBFToTargets(newRBFNeuron);
00175 
00176                         // Set the new RBFNeuron's activation high because it is located 
00177                         // right on the current data point.
00178                         newRBFNeuron->setFiringRate(1);
00179 
00180                         // Save the new RBFNeuron in the active Neuron list.
00181                         mActiveNeurons.push_back(newRBFNeuron);
00182                 }
00183         }
00184 
00185         void RBFPopulation::createNeuron(unsigned int id)
00186         {
00187                 RBFNeuron* neuron = new RBFNeuron(id);
00188                 mNeurons.push_back(neuron);
00189         }
00190 
00191         void RBFPopulation::makeNewRBF(const RBFInputData& inputData)
00192         {
00193                 // Create the new RBFNeuron.
00194                 createNeuron((unsigned int)mNeurons.size());
00195                 RBFNeuron* newRBFNeuron = static_cast<RBFNeuron*>(mNeurons.back());
00196 
00197                 // The RBF's "new RBF threshold" is the RBF's "personal space."  
00198                 // If any points fall within this distance from its center, no 
00199                 // new RBFs will be created.  Since the approximate distance 
00200                 // between each RBF along a given dimension is 2 / resolution, 
00201                 // we'll use it as the threshold value.  This value must be 
00202                 // related to the resolution because this value will affect 
00203                 // the total number of RBFs created in the dynamic case (which 
00204                 // is the purpose of the resolution parameter).
00205                 real newRBFThreshold = 2 / (real)mContinuousResolution;
00206 
00207                 // mStdDevWidth must be >= 0.25 * newRBFThreshold to ensure 
00208                 // that the RBFs creation threshold distance isn't beyond 
00209                 // the activation threshold.  The 0.25 comes from the fact 
00210                 // that we set the activation threshold to 4 * stdDevWidth 
00211                 // in RBFNeuron::init.
00212                 assert(mStdDevWidth >= (real)0.25 * newRBFThreshold);
00213 
00214                 // Initialize the RBF.  
00215                 newRBFNeuron->init(mStdDevWidth, newRBFThreshold, inputData);
00216         }
00217 
00218         void RBFPopulation::connectNewRBFToTargets(Neuron* n)
00219         {
00220                 // Connect the new RBFNeuron to the target Populations by 
00221                 // notifying the output Projections of the new Neuron.
00222                 unsigned int numProjections = (unsigned int)mOutputProjections.size();
00223                 for (unsigned int i = 0; i < numProjections; ++i)
00224                 {
00225                         mOutputProjections[i]->addPreNeuron(n);
00226                 }
00227         }
00228 
00229         unsigned int RBFPopulation::getNumActiveNeurons()const
00230         {
00231                 return (unsigned int)mActiveNeurons.size();
00232         }
00233 
00234         Neuron* RBFPopulation::getActiveNeuron(unsigned int i)
00235         {
00236                 return mActiveNeurons.at(i);
00237         }
00238 
00239         real RBFPopulation::computeMaxActivationSum()const
00240         {
00241                 // The following computes the maximum possible activation sum of all 
00242                 // RBFs.  We can then use this value to adjust the learning rate to 
00243                 // ensure stable learning.  The method we use here depends on 
00244                 // whether the RBF std. dev. width (mStdDevWidth) is constant or 
00245                 // if it depends on the resolution.
00246                 real maxActivationSum = 0;
00247 
00248                 if (0 == mNumContinuousDimensions)
00249                 {
00250                         // We only have discrete inputs (or no inputs at all), so there 
00251                         // will only be 1 RBF active at once.
00252                         maxActivationSum = 1;
00253                 }
00254                 else
00255                 {
00256                         // RBF ACTIVATION SUM METHOD 1: Assuming std. dev. width depends 
00257                         // on resolution.  In this case, we will use the experimentally-
00258                         // determined relationship: sum = 2.5^n, where n is the number 
00259                         // of continuous dimensions.
00260                         maxActivationSum = globals::pow((real)2.5, 
00261                                 (real)mNumContinuousDimensions);
00262 
00268                         //assert((real)0.5 == mStdDevWidth);
00269                         //maxActivationSum = (real)0.7477 * globals::pow((real)0.42, 
00270                         //      (real)mNumContinuousDimensions - 1) * globals::pow(
00271                         //      (real)mContinuousResolution, (real)mNumContinuousDimensions);
00272                 }
00273 
00274                 return maxActivationSum;
00275         }
00276 }

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