ModelManager.C

Go to the documentation of this file.
00001 /*!@file Component/ModelManager.C manages a model as collection of ModelComponents */
00002 
00003 // //////////////////////////////////////////////////////////////////// //
00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2003   //
00005 // by the University of Southern California (USC) and the iLab at USC.  //
00006 // See http://iLab.usc.edu for information about this project.          //
00007 // //////////////////////////////////////////////////////////////////// //
00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00010 // in Visual Environments, and Applications'' by Christof Koch and      //
00011 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00012 // pending; application number 09/912,225 filed July 23, 2001; see      //
00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00014 // //////////////////////////////////////////////////////////////////// //
00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00016 //                                                                      //
00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00018 // redistribute it and/or modify it under the terms of the GNU General  //
00019 // Public License as published by the Free Software Foundation; either  //
00020 // version 2 of the License, or (at your option) any later version.     //
00021 //                                                                      //
00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00025 // PURPOSE.  See the GNU General Public License for more details.       //
00026 //                                                                      //
00027 // You should have received a copy of the GNU General Public License    //
00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00030 // Boston, MA 02111-1307 USA.                                           //
00031 // //////////////////////////////////////////////////////////////////// //
00032 //
00033 // Primary maintainer for this file: Laurent Itti <itti@usc.edu>
00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Component/ModelManager.C $
00035 // $Id: ModelManager.C 14253 2010-11-20 01:52:00Z rand $
00036 //
00037 
00038 #include "Component/ModelManager.H"
00039 
00040 #include "Component/CmdlineOptionManager.H"
00041 #include "Component/GlobalOpts.H"
00042 #include "Component/ParamMap.H"
00043 #include "Util/AllocAux.H"
00044 #include "Util/CpuTimer.H"
00045 #include "Util/MathFunctions.H"
00046 #include "Util/fpe.H"
00047 #include "Util/fpu.H"
00048 #include "Util/log.H"
00049 #include "Util/terminate.H"
00050 #include "Util/version.H"
00051 #include "rutz/atomic.h"
00052 #include "rutz/demangle.h"
00053 #include "rutz/prof.h"
00054 
00055 #include <cstdlib>         // for getenv()
00056 #include <iostream>
00057 #include <string>
00058 #include <typeinfo>
00059 #include <cstdio>          // for fopen()
00060 
00061 using std::cerr;
00062 using std::endl;
00063 using std::string;
00064 
00065 // ##############################################################
00066 //! This is the internal implementation struct for ModelManager.
00067 /*! We use the implementation approach so that clients of ModelManager
00068     aren't exposed to its implementation details (and thus they don't
00069     have to recompile everytime something changes in ModelManager's
00070     implementation). */
00071 struct ModelManager::Impl
00072 {
00073   Impl(ModelManager* owner)
00074     :
00075     paramShowHelpMsg(&OPT_ShowHelpMessage, owner),
00076     paramShowVersion(&OPT_ShowVersion, owner),
00077     paramShowSvnVersion(&OPT_ShowSvnVersion, owner),
00078     paramCheckPristine(&OPT_CheckPristine, owner),
00079     paramDebugMode(&OPT_DebugMode, owner),
00080     paramUsingFPE(&OPT_UsingFPE, owner),
00081     paramFpuPrecision(&OPT_FpuPrecision, owner),
00082     paramFpuRoundingMode(&OPT_FpuRoundingMode, owner),
00083     paramTestMode(&OPT_TestMode, owner),
00084     paramProfileFile(&OPT_ProfileOutFile, owner),
00085     paramLogVerb(&OPT_LogVerb, owner),
00086     paramEchoArgs(&OPT_EchoArgs, owner),
00087     paramMemCaching(&OPT_MemCaching, owner),
00088     userLogVerb(MYLOGVERB)
00089   {
00090     // WARNING! Don't call any code here; instead call code from
00091     // ModelManager's constructor. That's because if we call any code
00092     // here that ends up back in some other ModelManager function, the
00093     // rep will not yet be initialized -- it will be null or garbage
00094     // -- since we haven't yet returned from the Impl constructor.
00095   }
00096 
00097   CmdlineOptionManager com;
00098 
00099   OModelParam<bool> paramShowHelpMsg;   //!< print help message?
00100   OModelParam<bool> paramShowVersion;   //!< print full version info?
00101   OModelParam<bool> paramShowSvnVersion;//!< print svn repo version?
00102   OModelParam<bool> paramCheckPristine; //!< check if the source is pristine?
00103   OModelParam<bool> paramDebugMode;     //!< use debug mode?
00104   OModelParam<bool> paramUsingFPE;      //!< use floating-point exceptions?
00105   OModelParam<FpuPrecision> paramFpuPrecision; //!< floating-point precision
00106   OModelParam<FpuRoundingMode> paramFpuRoundingMode; //!< floating-point rounding mode
00107   OModelParam<bool> paramTestMode;      //!< use test mode?
00108   OModelParam<string> paramProfileFile; //!< Where to save profiling information
00109   rutz::shared_ptr<OModelParam<string> > paramLoadConfigFname; //!< Name of a config file to load up
00110   rutz::shared_ptr<OModelParam<string> > paramSaveConfigFname; //!< Name of a config file to save to
00111   OModelParam<string> paramLogVerb; //!< Log verbosity level
00112   OModelParam<bool> paramEchoArgs; //!< echo command-line args during start()?
00113   OModelParam<bool> paramMemCaching;
00114 
00115   bool autoLoadConfig; //!< Load ~/.execname just before parsing command-line
00116 
00117   bool didSave;      //!< was saveConfig() already called?
00118 
00119   const int userLogVerb; //!< the log verbosity level set by the user before the ModelManager was created
00120 
00121   CpuTimer timer;
00122 };
00123 
00124 
00125 // ##############################################################
00126 // ##############################################################
00127 // ModelManager member functions
00128 // ##############################################################
00129 // ##############################################################
00130 
00131 // ##############################################################
00132 ModelManager::ModelManager(const string& descrName,
00133                            const string& tag,
00134                            const bool loadCfgOpt,
00135                            const bool saveCfgOpt,
00136                            const bool autoLoadCfg) :
00137   ModelComponent(descrName, tag),
00138   rep(new Impl(this))
00139 {
00140   // install a fancy termination handler that will print a backtrace
00141   invt_install_fancy_terminate();
00142 
00143   this->setManager(rep->com);
00144 
00145   // NOTE no need to do explicit requestOption() here anymore;
00146   // instead, requestOption() during ModelComponent's implementation
00147   // of exportOptions() -- nevertheless, request the debug mode option
00148   // right away so that we aren't needlessly noisy at the beginning of
00149   // the program run:
00150   this->requestOption(rep->paramDebugMode);
00151 
00152   // do we want an option to load a config file?
00153   if (loadCfgOpt) {
00154     rep->paramLoadConfigFname =
00155       OModelParam<string>::make(&OPT_LoadConfigFile, this);
00156   }
00157 
00158   // do we want an option to save a config file?
00159   if (saveCfgOpt) {
00160     rep->paramSaveConfigFname =
00161       OModelParam<string>::make(&OPT_SaveConfigFile, this);
00162   }
00163 
00164   // keep track of autoload:
00165   rep->autoLoadConfig = autoLoadCfg;
00166 
00167   // keep track of whether saveConfig() has been called:
00168   rep->didSave = false;
00169 
00170   // pick up settings from relevant environment variables now, before
00171   // the command-line is parsed, so that command-line options can
00172   // override the environment variables -- NOTE that if this becomes a
00173   // commonly-used idiom, then it might make sense to add a new
00174   // setOptionFromEnvironment() virtual function to OptionManager, and
00175   // implement it here in ModelManager
00176   const char* precision = getenv("INVT_FPU_PRECISION");
00177 
00178   if (precision != 0)
00179     {
00180       this->setOptionValString(rep->paramFpuPrecision.getOptionDef(),
00181                                precision);
00182     }
00183 
00184   const char* rounding = getenv("INVT_FPU_ROUNDING_MODE");
00185 
00186   if (rounding != 0)
00187     {
00188       this->setOptionValString(rep->paramFpuRoundingMode.getOptionDef(),
00189                                rounding);
00190     }
00191 }
00192 
00193 // ##############################################################
00194 ModelManager::~ModelManager()
00195 {
00196   if (this->started())
00197     this->stop();
00198 
00199   // NOTE: one could be tempted to call saveConfig() here for
00200   // automatic persistence of our ModelParam values. But that would be
00201   // dangerous as some of our ModelComponents may already have been
00202   // destroyed by the time we get here. So, saveConfig() should be
00203   // called manually, at a point in the code where all ModelComponents
00204   // are still alive.
00205 
00206   // let our components know that we are gone:
00207   managerDestroyed();
00208 
00209   delete rep;
00210 
00211   // ugly const_cast to set rep=0 here, but the ugliness is justified
00212   // the fact that it allows us to ASSERT(rep!=0) in our other
00213   // functions to make sure that people don't try to use us after we
00214   // have already been destroyed
00215   *(const_cast<Impl**>(&rep)) = 0;
00216 }
00217 
00218 // ##############################################################
00219 void ModelManager::allowOptions(const int mask)
00220 {
00221   ASSERT(rep != 0);
00222   rep->com.allowOptions(mask);
00223 }
00224 
00225 // ##############################################################
00226 void ModelManager::requestOption(OptionedModelParam& p,
00227                                  const bool useMyVal)
00228 {
00229   ASSERT(rep != 0);
00230   rep->com.requestOption(p, useMyVal);
00231 }
00232 
00233 // ##############################################################
00234 void ModelManager::unRequestOption(OptionedModelParam& p)
00235 {
00236   if (rep == 0)
00237     LERROR("Oops, it looks like some ModelComponent is trying "
00238            "to unrequest an OptionedModelParam during its "
00239            "destructor, but doesn't know that the ModelManager "
00240            "has already been destroyed. A likely cause of this "
00241            "is that the ModelComponent in question was never "
00242            "passed to addSubComponent().");
00243   ASSERT(rep != 0);
00244   rep->com.unRequestOption(p);
00245 }
00246 
00247 // ##############################################################
00248 void ModelManager::requestOptionAlias(const ModelOptionDef* def)
00249 {
00250   ASSERT(rep != 0);
00251   rep->com.requestOptionAlias(def);
00252 }
00253 
00254 // ##############################################################
00255 void ModelManager::setOptionValString(const ModelOptionDef* def,
00256                                       const string& val)
00257 {
00258   ASSERT(rep != 0);
00259   rep->com.setOptionValString(def, val);
00260 }
00261 
00262 // ##############################################################
00263 string ModelManager::getOptionValString(const ModelOptionDef* def)
00264 {
00265   ASSERT(rep != 0);
00266   return rep->com.getOptionValString(def);
00267 }
00268 
00269 // ##############################################################
00270 bool ModelManager::isOptionRequested(const ModelOptionDef* def) const
00271 {
00272   ASSERT(rep != 0);
00273   return rep->com.isOptionRequested(def);
00274 }
00275 
00276 // ##############################################################
00277 bool ModelManager::parseCommandLine(const int argc,
00278                                     const char** argv,
00279                                     const char* usage,
00280                                     const int minarg,
00281                                     const int maxarg)
00282 {
00283   ASSERT(rep != 0);
00284 
00285   // export options if that hasn't been done already
00286   if (this->hasBeenExported() == false)
00287     exportOptions(MC_RECURSE);
00288 
00289   // let's get our application name:
00290   if (argc <= 0)
00291     LFATAL("expected argc >= 1, got argc=%d", argc);
00292   string procname(argv[0]);
00293   uint ii = procname.rfind('/'); // skip the path; get just the filename:
00294   if (ii < procname.size()) procname = procname.substr(ii + 1);
00295 
00296   // if we wanted to automatically load a config from ~/.execname,
00297   // let's do that now:
00298   if (rep->autoLoadConfig && getenv("HOME"))
00299     {
00300       string fname = string(getenv("HOME")) + "/." + procname;
00301       FILE* tryit = fopen(fname.c_str(), "r");
00302       if (tryit) {   // config file exists; let's load it:
00303         fclose(tryit);
00304         LINFO("Autoloading configuration from '%s'", fname.c_str());
00305         ParamMap pmap; pmap.load(fname.c_str());
00306         readParamsFrom(pmap);
00307       }
00308     }
00309 
00310   return rep->com.parseCommandLine(argc, argv, usage, minarg, maxarg);
00311 }
00312 
00313 // ##############################################################
00314 bool ModelManager::parseCommandLine(const int argc,
00315                                     char* const* argv,
00316                                     const char* usage,
00317                                     const int minarg,
00318                                     const int maxarg)
00319 {
00320   std::vector<const char*> argv2;
00321   while (*argv != 0)
00322     argv2.push_back(*argv++);
00323   argv2.push_back(0);
00324 
00325   ASSERT(int(argv2.size()) == (argc + 1));
00326 
00327   return this->parseCommandLine(argc, &argv2[0], usage, minarg, maxarg);
00328 }
00329 
00330 // ##############################################################
00331 bool ModelManager::parseCommandLineCore(const int argc, const char** argv)
00332 {
00333   ASSERT(rep != 0);
00334   return rep->com.parseCommandLineCore(argc, argv);
00335 }
00336 
00337 // ##############################################################
00338 bool ModelManager::parseCommandLineCore(const char* args)
00339 {
00340   ASSERT(rep != 0);
00341   return rep->com.parseCommandLineCore(args);
00342 }
00343 
00344 // ##############################################################
00345 uint ModelManager::numExtraArgs() const
00346 {
00347   ASSERT(rep != 0);
00348   return rep->com.numExtraArgs();
00349 }
00350 
00351 // ##############################################################
00352 string ModelManager::getExtraArg(const uint num) const
00353 {
00354   ASSERT(rep != 0);
00355   return rep->com.getExtraArg(num);
00356 }
00357 
00358 // ##############################################################
00359 uint ModelManager::numOptionDefs() const
00360 {
00361   ASSERT(rep != 0);
00362   return rep->com.numOptionDefs();
00363 }
00364 
00365 // ##############################################################
00366 uint ModelManager::getOptionDefs(const ModelOptionDef** arr, uint narr)
00367 {
00368   ASSERT(rep != 0);
00369   return rep->com.getOptionDefs(arr, narr);
00370 }
00371 
00372 // ##############################################################
00373 const ModelOptionDef* ModelManager::findOptionDef(const char* name) const
00374 {
00375   return rep->com.findOptionDef(name);
00376 }
00377 
00378 // ##############################################################
00379 bool ModelManager::isOptionDefUsed(const ModelOptionDef* def) const
00380 {
00381   ASSERT(rep != 0);
00382   return rep->com.isOptionDefUsed(def);
00383 }
00384 
00385 // ##############################################################
00386 void ModelManager::loadConfig()
00387 {
00388   ASSERT(rep != 0);
00389   if (rep->paramLoadConfigFname.get() != 0 &&
00390       rep->paramLoadConfigFname->getVal().empty() == false)
00391     this->loadConfig(rep->paramLoadConfigFname->getVal());
00392 }
00393 
00394 // ##############################################################
00395 void ModelManager::loadConfig(const string& fname)
00396 {
00397   LINFO("Loading configuration from '%s'", fname.c_str());
00398   ParamMap pmap; pmap.load(fname.c_str());
00399   this->readParamsFrom(pmap);
00400 }
00401 
00402 // ##############################################################
00403 void ModelManager::saveConfig() const
00404 {
00405   ASSERT(rep != 0);
00406   if (rep->paramSaveConfigFname.get() != 0 &&
00407       rep->paramSaveConfigFname->getVal().empty() == false)
00408     this->saveConfig(rep->paramSaveConfigFname->getVal());
00409 }
00410 
00411 // ##############################################################
00412 void ModelManager::saveConfig(const string& fname) const
00413 {
00414   LINFO("Saving configuration to '%s'", fname.c_str());
00415   ParamMap pmap; this->writeParamsTo(pmap);
00416   pmap.format(fname);
00417 }
00418 
00419 // ##############################################################
00420 void ModelManager::start1()
00421 {
00422   ASSERT(rep != 0);
00423 
00424   // echo the command-line if the user requested that:
00425   if (rep->paramEchoArgs.getVal())
00426     {
00427       for (uint i = 0; i < rep->com.numArgs(); ++i)
00428         LINFO("argv[%u]='%s'", i, rep->com.getArg(i).c_str());
00429     }
00430 
00431   // report a bunch of settings:
00432   LINFO("Debug: %s, FPE: %s, FpuPrecision: %s, FpuRounding: %s, "
00433         "TestMode: %s, AtomicIntType: %s",
00434         rep->paramDebugMode.getVal() ? "ON" : "OFF",
00435         rep->paramUsingFPE.getVal() ? "ON" : "OFF",
00436         convertToString(getFpuPrecision()).c_str(),
00437         convertToString(getFpuRoundingMode()).c_str(),
00438         rep->paramTestMode.getVal() ? "ON" : "OFF",
00439         rutz::demangled_name(typeid(rutz::atomic_int_t)));
00440 
00441   // did we want a debug printout?
00442   if (rep->paramDebugMode.getVal()) {
00443     std::cerr<<"==================== MODEL PARAMETERS ====================\n";
00444     printout(std::cerr);
00445     std::cerr<<"==========================================================\n";
00446   }
00447 
00448   // if saveConfig() has not been called yet, let's do it now just
00449   // before we start all our components:
00450   if (rep->didSave == false) { rep->didSave = true; saveConfig(); }
00451 }
00452 
00453 // ##############################################################
00454 void ModelManager::start2()
00455 {
00456   ASSERT(rep != 0);
00457 
00458   rep->timer.reset();
00459 }
00460 
00461 // ##############################################################
00462 void ModelManager::stop1()
00463 {
00464   ASSERT(rep != 0);
00465 
00466   rep->timer.mark();
00467   rep->timer.report("from start() to stop()");
00468 }
00469 
00470 // ##############################################################
00471 void ModelManager::paramChanged(ModelParamBase* const param,
00472                                 const bool valueChanged,
00473                                 ParamClient::ChangeStatus* status)
00474 {
00475   ASSERT(rep != 0);
00476 
00477   ModelComponent::paramChanged(param, valueChanged, status);
00478 
00479   // change log verbosity level?
00480   if (param == &rep->paramLogVerb) {
00481     string v = rep->paramLogVerb.getVal();
00482 
00483     const int oldLogVerb = MYLOGVERB;
00484 
00485     if (v.compare("Debug") == 0) MYLOGVERB = LOG_DEBUG;
00486     else if (v.compare("Info") == 0) MYLOGVERB = LOG_INFO;
00487     else if (v.compare("Error") == 0) MYLOGVERB = LOG_ERR;
00488     else if (v.compare("Fatal") == 0) MYLOGVERB = LOG_CRIT;
00489     else if (v.compare("Default") == 0) MYLOGVERB = rep->userLogVerb;
00490     else
00491       LFATAL("Invalid log verbosity value '%s' (valid are: "
00492              "[Debug|Info|Error|Fatal|Default])", v.c_str());
00493 
00494     if (MYLOGVERB != oldLogVerb)
00495       LERROR("Switching log verbosity to %s", v.c_str());
00496   }
00497 
00498   // show full version info?
00499   if (param == &rep->paramShowVersion) {
00500     if (rep->paramShowVersion.getVal()) {
00501       // print the version to stdout and exit
00502       fprintf(stdout, "%s\n", fullversion());
00503       exit(0);
00504     }
00505   }
00506 
00507   // show svn repo version?
00508   else if (param == &rep->paramShowSvnVersion) {
00509     if (rep->paramShowSvnVersion.getVal()) {
00510       // print the version to stdout and exit
00511       fprintf(stdout, "%s\n", svnversion());
00512       exit(0);
00513     }
00514   }
00515 
00516   // check if the source is pristine?
00517   else if (param == &rep->paramCheckPristine) {
00518     if (rep->paramCheckPristine.getVal()) {
00519       exit(isSourcePristine() ? 0 : 1);
00520     }
00521   }
00522 
00523   // debug mode on/off?
00524   else if (param == &rep->paramDebugMode) {
00525     if (rep->paramDebugMode.getVal()) MYLOGVERB = LOG_DEBUG;
00526     else MYLOGVERB = rep->userLogVerb;
00527   }
00528 
00529   // floating-point exceptions on/off?
00530   else if (param == &rep->paramUsingFPE && valueChanged) {
00531     if (rep->paramUsingFPE.getVal()) fpExceptionsOn();
00532     else fpExceptionsOff();
00533   }
00534 
00535   // floating-point precision?
00536   else if (param == &rep->paramFpuPrecision) {
00537     setFpuPrecision(rep->paramFpuPrecision.getVal());
00538   }
00539 
00540   // floating-point rounding mode?
00541   else if (param == &rep->paramFpuRoundingMode) {
00542     setFpuRoundingMode(rep->paramFpuRoundingMode.getVal());
00543   }
00544 
00545   // test mode on/off?
00546   else if (param == &rep->paramTestMode) {
00547     if (rep->paramTestMode.getVal()) {
00548       // will produce deterministic pseudo-random sequences
00549       initRandomNumbersZero();
00550       setOptionValString(&OPT_UseRandom, "false");
00551     } else {
00552       initRandomNumbers();
00553       setOptionValString(&OPT_UseRandom, "true");
00554     }
00555   }
00556 
00557   // save profiling information?
00558   else if (param == &rep->paramProfileFile) {
00559     // NOTE: we require an explicit "none" instead of just the empty
00560     // string to request no profiling output -- that way, if certain
00561     // programs want to set up their own default location for the
00562     // profile file, then we won't accidentally mess up their default
00563     // with an empty string.
00564     if (rep->paramProfileFile.getVal().compare("none") == 0)
00565       {
00566         rutz::prof::print_at_exit(false);
00567       }
00568     else if (rep->paramProfileFile.getVal().empty())
00569       {
00570         // do nothing if it's an empty string, just leave things as
00571         // they are
00572       }
00573     else
00574       {
00575         rutz::prof::print_at_exit(true);
00576         rutz::prof::prof_summary_file_name
00577           (rep->paramProfileFile.getVal().c_str());
00578 
00579         // NOTE: we could also have a command-line option to control
00580         // whether the timing mode is RUSAGE (i.e. cpu usage) or
00581         // WALLCLOCK (i.e., real elapsed time)
00582         rutz::prof::set_timing_mode(rutz::prof::RUSAGE);
00583       }
00584   }
00585 
00586   else if (param == rep->paramLoadConfigFname.get())
00587     {
00588       // if processing this option just changed our loadConfigFile
00589       // parameter, that means that we just parsed an option that
00590       // specified that value. Let's load up the file immediately:
00591       loadConfig();
00592     }
00593 
00594   else if (param == &rep->paramMemCaching)
00595     {
00596       invt_allocation_allow_caching(rep->paramMemCaching.getVal());
00597     }
00598 }
00599 
00600 // ##############################################################
00601 bool ModelManager::debugMode() const
00602 {
00603   ASSERT(rep != 0);
00604   return rep->paramDebugMode.getVal();
00605 }
00606 
00607 // ##############################################################
00608 void ModelManager::setFPE(bool val)
00609 {
00610   ASSERT(rep != 0);
00611   rep->paramUsingFPE.setVal(val);
00612 }
00613 
00614 // ##############################################################
00615 void ModelManager::clearExtraArgs()
00616 {
00617   ASSERT(rep != 0);
00618   rep->com.clearExtraArgs();
00619 }
00620 
00621 // ##############################################################
00622 void ModelManager::unRequestTestMode()
00623 { unRequestOption(rep->paramTestMode); }
00624 
00625 // ##############################################################
00626 void ModelManager::unRequestUsingFPE()
00627 { unRequestOption(rep->paramUsingFPE); }
00628 
00629 // ##############################################################
00630 /* So things look consistent in everyone's emacs... */
00631 /* Local Variables: */
00632 /* indent-tabs-mode: nil */
00633 /* End: */
Generated on Sun May 8 08:04:42 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3