howto-scripting.dxy

00001         -*- mode: text; fill-column: 70; indent-tabs-mode: nil -*-
00002              $Id: README 4939 2005-06-28 07:16:30Z zhanshi $
00003 
00004                    ------------------------------------
00005                    README for C++/Tcl scripting engine
00006                    ------------------------------------
00007 
00008 NOTE: If you're reading this file as a flat text file, you'll notice
00009 that there is some additional markup, which is used to generate an
00010 HTML version of this file with the doxygen tool. Nevertheless, this
00011 file should remain readable as plain text.
00012 
00013 /** \page howto-scripting Introduction to the C++/Tcl scripting engine
00014 
00015 This is an introduction to a scripting engine that allows the C++
00016 objects in the iLab Neuromorphic Vision Toolkit to be manipulated
00017 through a tcl scripting interface.
00018 
00019 Table of contents:
00020 
00021 - \ref fortheimpatient
00022 - \ref overview
00023 - \ref neuroscript
00024 - \ref walkthrough
00025 
00026 <!--############################################################--><hr>
00027 
00028 \section fortheimpatient 1. For the impatient
00029 
00030   For the impatient:
00031 
00032   - the main program for the script interpreter is bin/invt, source
00033     code in Script/invt.C (underneath src/ directory)
00034   - additional script interface code is in src/Script
00035   - infrastructure code for the c++/tcl scripting engine is drawn from
00036     the groovx (http://ilab.usc.edu/rjpeters/groovx/) project, and
00037     sits in src/rutz, src/nub, and src/tcl
00038   - there is a script implementation of ezvision in bin/ezvision.tcl,
00039     which you can run with bin/invt: "./bin/invt bin/ezvision.tcl
00040     --args --that --you --normally --pass --to --ezvision"
00041   - this script implementation (ezvision.tcl) passes both the short and
00042     long ezvision test suties
00043 
00044 <!--############################################################--><hr>
00045 
00046 \section overview 2. Overview
00047 
00048   In saliency/ezvision.tcl is a translation of ezvision.C into
00049   script. The script version passes the ezvision test suite (do "make
00050   bin/invt; cd tests; ./test_scriptvision_blackbox.tcl") and the long
00051   movies test suite ("make bin/invt; cd tests;
00052   ./testlong_script_movies_blackbox.tcl"). It's less than 2x slower
00053   than the full C++ ezvision -- short ezvision test takes 13s with the
00054   C++ version vs. 23s with the tcl script (77% slower), while the long
00055   ezvision movies test takes 326s in C++ and 363s in Tcl (11% slower).
00056 
00057   This system is based on some of the infrastructure from "GroovX"
00058   (http://ilab.usc.edu/rjpeters/groovx/). The imported source from
00059   groovx is in src/rutz (utility stuff in "rutz::" namespace), src/nub
00060   (object base class plus smart pointers in "nub::" namespace), and
00061   src/tcl (facilities for exposing c++ code through tcl scripts).
00062 
00063   The only changes that are required to existing invt code are (1)
00064   ModelComponent derives from a new base class, nub::object, and (2)
00065   we use a new smart ptr type (nub::soft_ref) instead of SharedPtr to
00066   hold ModelComponent derivatives. More info below. In any case, the
00067   scripting layer is not intrusive in the sense that none of the core
00068   code (Image, Neuro, Devices, Media, etc.) has to know anything about
00069   scripting or scriptability, except that we have to use the right
00070   smart pointer types. The syntax for using the smart pointers
00071   themselves is identical between SharedPtr and nub::soft_ref.
00072 
00073   The script interface for invt is defined in src/Script. The main
00074   program is in Script/invt.C -- it basically gives a list of the
00075   script modules that we want to load, and then calls off to some
00076   library in src/tcl to load those packages and then start looping,
00077   processing user input.
00078 
00079   Then there are the script modules in src/Script. For now, we have:
00080 
00081   - Script/ImageScript.C
00082   - Script/ImageScript.H
00083   - Script/MediaScript.C
00084   - Script/MediaScript.H
00085   - Script/ModelScript.C
00086   - Script/ModelScript.H
00087   - Script/NeuroScript.C
00088   - Script/NeuroScript.H
00089 
00090   For each C++ class that we want to export, we define a
00091   Classname_Init() function that sets up the script commands for that
00092   class. These *_Init() functions are what we enumerate in the main
00093   program. However, it is also possible to dynamically load shared
00094   libraries containing *_Init() functions into a running tcl
00095   program. That means that we could have true plug-ins, where new code
00096   never has to be linked into the main program, it just gets loaded at
00097   runtime.
00098 
00099 <!--############################################################--><hr>
00100 
00101 \section neuroscript 3. Script interface example: NeuroScript
00102 
00103   Look at Script/NeuroScript.H. There we have Brain_Init() and
00104   Stdbrain_Init() (note that the functions are extern "C" and have the
00105   first letter capitalized, and all the rest lowercase -- this is
00106   important to allow dynamic loading -- that way if you tell tcl a
00107   package name, it can deterministically figure out what the name of
00108   the *_Init() function should be, and find it with dlsym()). Then
00109   there are also some functions for installing component types into
00110   the object factory, so that within a script we can create objects
00111   from their class name.
00112 
00113   On to Script/NeuroScript.C.
00114 
00115   Here's an overview of how the object-management system works. We use
00116   intrusive reference counting -- the ref count is within the object
00117   itself; we inject this into the ModelComponent hierarchy by having
00118   ModelComponent derive from nub::object. Because the reference count
00119   is intrusive, we don't have to worry about constructing multiple
00120   independent smart pointers from the same object, like we do with
00121   SharedPtr -- in this case, they always share the same reference
00122   count. We have nub::ref and nub::soft_ref smart pointer classes,
00123   nub::ref is "strong", meaning that its pointee can never be
00124   null. nub::soft_ref allows null pointees. Each nub::object gets a
00125   unique nub::uid when it is created. When we construct a nub::ref or a
00126   nub::soft_ref from an nub::object, we have the option to insert that
00127   nub::object into the nub::objectdb, which is essentially a
00128   std::map<nub::uid, soft_ref<nub::object>>. That is, it allows us to
00129   retrieve an object given just its nub::uid. This is how we expose objects
00130   to the tcl script -- via their nub::uid. So we are essentially using
00131   integer handles to the objects.
00132 
00133   (BTW, I also have the ability to do weak pointers -- like weak
00134   references in Java -- that don't prevent their pointee from being
00135   destroyed. Instead, the weak pointers just silently become null when
00136   their pointee goes away -- so there's no risk of dangling pointers,
00137   and the weak pointers can be used to allow safe "back-pointers" up
00138   the object hierarchy without creating a strong-reference cycle that
00139   would prevent the entire cycle of objects from being destroyed.)
00140 
00141   OK, skip down to Brain_Init() in Script/NeuroScript.C. We start
00142   a package with GVX_PKG_CREATE(). We inherit_pkg("ModelComponent") to
00143   bring in the script commands that were defined for ModelComponent
00144   (so we get "start" etc., see Modecomponent_Init() in
00145   Script/ModelScript.C to see what is exposed). We
00146   def_basic_type_cmds(), which allows us in script to find all current
00147   Brain objects, count them, query whether some object is a Brain or
00148   not. We registerComponentCreator<Brain>(), which puts a function
00149   into the nub::obj_factory (nub/objfactory.h) that knows how to
00150   create Brain objects. The creator function knows how to find a
00151   global ModelManager that is defined in ModelScript.C, and use that
00152   ModelManager to create the Brain.
00153 
00154   Then we start getting into the pkg->def()'s. Here is where we are
00155   defining the script commands. The pkg->def() takes 4 params: (1) the
00156   name of the script command, (2) a human-readable string describing
00157   the arguments that the command takes, (3) the pointer-to-member or
00158   function address of the C++ function we want to make scriptable, and
00159   (4) SRC_POS, which is just a wrapper around __FILE__ and __LINE__
00160   that lets us figure out, from inside a Tcl script, where a
00161   particular script wrapper was defined in the C++; that can be
00162   helpful for debugging.
00163 
00164   What happens with pkg->def() is that we set up a big template thingy
00165   that gets the tcl script call as input (just a list of tcl objects),
00166   figures out how to convert those to native C++ types, then calls the
00167   C++ function, then converts the result back to Tcl. The command also
00168   does other nice stuff like ensure that the number of input arguments
00169   is correct, etc.
00170 
00171   The c++ <-> tcl conversions are handled by a family of overloads
00172   that know how to do the individual conversions (basically like our
00173   convertToString() and convertFromString()). E.g., there is a
00174   converter from nub::ref->Tcl that returns the int value of the
00175   object's nub::uid, and a convert from Tcl->nub::ref that gets an int,
00176   then looks up an object with that nub::uid in the nub::objectdb, and
00177   casts it to the desired type.
00178 
00179   Most of the time, the builtin c++ <-> tcl conversions will do the
00180   right thing, and it's possible to do a pkg->def() with just the
00181   address of an existing member or free function. Other times, it
00182   makes more sense to write a thin c++ wrapper, that does some more
00183   intelligent c++/tcl translation, that gets passed to pkg->def()
00184   instead. See for example brainEvolve() in Script/NeuroScript.C,
00185   which wraps Brain::evolve() so that instead of returning values
00186   through non-const reference parameters (which doesn't translate well
00187   into a script language with primarily value semantics), we just
00188   return all the return values in a tcl list, which we can unpack on
00189   the script side (see ezvision.tcl).
00190 
00191   BTW, casting brings up the issue of exceptions -- each script
00192   command call is internally wrapped in a try/catch block (see
00193   tcl::command_group::invoke_raw in tcl/commandgroup.cc around line
00194   382), so if any exceptions are raised while tcl is calling back to
00195   c++, the command machinery will catch the exception and translate
00196   into a human-readable error message on the script interpreter
00197   console (i.e., the program doesn't abort).
00198 
00199 
00200 <!--############################################################--><hr>
00201 
00202 \section walkthrough 4. Walkthrough with bin/invt
00203 
00204   Here's an annotated session transcript. You can play along by doing
00205   "make bin/invt", then run "./bin/invt -nw" (the -nw means
00206   "nowindow"). The "./bin/invt 1>>>" is the prompt. You can use
00207   readline/history commands just like in bash (i.e., up-arrow to get
00208   previous commands, Esc-Del to kill the word behind the cursor,
00209   etc.). You can also use tab completion, but the only thing it will
00210   complete is filenames (i.e. it doesn't know how to complete script
00211   command names). Here goes:
00212 
00213   \code
00214 
00215     [iLab9 19:51 7687]$ ./bin/invt -nw
00216 
00217     ###########################################################################
00218     ###        iLab C++ Neuromorphic Vision Toolkit 3.1 (Jun 27 2005)       ###
00219     ###########################################################################
00220     ###  Copyright (c) 2001-2005 iLab and the Univ. of Southern California  ###
00221     ###                        <http://ilab.usc.edu>                        ###
00222     ###            Copyright (c) 1998-2004 Rob Peters and Caltech           ###
00223     ###                <http://ilab.usc.edu/rjpeters/groovx/>               ###
00224     ###  iLab C++ Neuromorphic Vision Toolkit is free software, covered by  ###
00225     ###   the GNU General Public License, and you are welcome to change it  ###
00226     ###       and/or distribute copies of it under certain conditions.      ###
00227     ###########################################################################
00228 
00229             startup time (tcl+tk)  0.009s (user)  0.002s (sys)  0.010s (wall)
00230             startup time (  iNVT)  0.030s (user)  0.000s (sys)  0.030s (wall)
00231 
00232   \endcode
00233 
00234   Let's find all current objects
00235 
00236   \code
00237     ./bin/invt 1>>> Obj::find_all
00238     1
00239   \endcode
00240 
00241   OK, there is one object, and its nub::uid is 1. Now let's see what
00242   its type is:
00243 
00244   \code
00245     ./bin/invt 2>>> Obj::type [Obj::find_all]
00246     ModelManager
00247   \endcode
00248 
00249   Cool, it's the global ModelManager that is constructed in
00250   Modelmanager_Init(). Let's see what params/subcomponents it
00251   currently has. We do "ModelManager::printout 1", where 1 is the
00252   nub::uid of the ModelManager.
00253 
00254   \code
00255     ./bin/invt 3>>> ModelManager::printout 1
00256     model: ShowHelpMessage = true
00257     model: DebugMode = false
00258     model: UsingFPE = false
00259     model: TestMode = false
00260     model: TextLogFile =
00261     model: LoadConfigFile =
00262     model: SaveConfigFile =
00263   \endcode
00264 
00265   In "real" code, we'd assign 1 to a variable with "set mm
00266   [ModelManager::find_all]", and then do "ModelManager::printout
00267   $mm". Let's do that now:
00268 
00269   \code
00270     ./bin/invt 4>>> set mm [ModelManager::find_all]
00271     1
00272     ./bin/invt 5>>> Obj::type $mm
00273     ModelManager
00274   \endcode
00275 
00276   Now let's try to "printout" an invalid nub::uid:
00277 
00278   \code
00279     ./bin/invt 6>>> ModelManager::printout 3
00280     rutz::error caught at src/tcl/commandgroup.cc:442:
00281     ModelManager::printout: at src/nub/refdetail.h:243:
00282     attempted to access invalid object in soft_ref<ModelComponent>
00283   \endcode
00284 
00285   OK, it caught our invalid access attempt. The source file line
00286   numbers show where the exception was caught
00287   (src/tcl/commandgroup.cc:442) and where it was thrown
00288   (src/nub/refdetail.h:243)
00289 
00290   Let's try to make a new object. First we try to create an object of
00291   type "blah".
00292 
00293   \code
00294     ./bin/invt 7>>> new blah
00295     rutz::error caught at src/tcl/tclcommandgroup.cc:442:
00296     new: at src/rutz/factory.h:224:
00297     known keys are:
00298             Brain
00299             InputFrameSeries
00300             OutputFrameSeries
00301             StdBrain
00302     unknown object type 'blah'
00303   \endcode
00304 
00305   OK, it doesn't know anything about 'blah', but it tells us the types
00306   that it does know about. These are the ones that are in the
00307   nub::obj_factory, in which we registered them with
00308   registerComponentCreator().
00309 
00310   Now let's make a brain, and capture its nub::uid in a variable
00311   called 'mybrain'
00312 
00313   \code
00314     ./bin/invt 8>>> set mybrain [new StdBrain]
00315     2
00316     ./bin/invt 9>>> puts "the value of mybrain is $mybrain"
00317     the value of mybrain is 2
00318   \endcode
00319 
00320   OK, its nub::uid is 2. Now if we ask to find all Brain objects:
00321 
00322   \code
00323     ./bin/invt 9>>> StdBrain::find_all
00324     2
00325     ./bin/invt 10>>> Brain::find_all
00326     2
00327   \endcode
00328 
00329   We get our StdBrain back from StdBrain::find_all. Note that
00330   Brain::find_all also finds our StdBrain even though StdBrain!=Brain,
00331   because StdBrain is a derived type of Brain.
00332 
00333   \code
00334     ./bin/invt 10>>> Obj::type $mybrain
00335     StdBrain
00336   \endcode
00337 
00338   There's its type. Now let's do Obj::find_all again:
00339 
00340   \code
00341     ./bin/invt 10>>> Obj::find_all
00342     1 2 3 4 5 6 7 8 9 10 11 12 13
00343   \endcode
00344 
00345   and get the object types:
00346 
00347   \code
00348     ./bin/invt 11>>> Obj::type [Obj::find_all]
00349     ModelManager StdBrain RetinaConfigurator SaccadeControllerConfigurator
00350     VisualCortexConfigurator SaliencyMapConfigurator
00351     TaskRelevanceMapConfigurator AttentionGuidanceMapConfigurator
00352     WinnerTakeAllConfigurator SimulationViewerConfigurator
00353     InferoTemporalConfigurator GistEstimatorConfigurator ShapeEstimator
00354   \endcode
00355 
00356   So there are all of the subcomponents of the StdBrain object that we
00357   just constructed.
00358 
00359   Let's play around with our StdBrain some more. Query some of its
00360   param values:
00361 
00362   \code
00363     ./bin/invt 12>>> StdBrain::param $mybrain IORtype
00364     Auto
00365   \endcode
00366 
00367   Now let's get a different param value -- and note that this is a
00368   good chance to make sure you're using the readline history editing
00369   feature of bin/invt: hit the up-arrow to retrieve the previous
00370   command (the one with 'IORtype'), then hit Esc-Delete to kill the
00371   'IORtype' word, then type 'UseRandom' and hit Enter:
00372 
00373   \code
00374     ./bin/invt 13>>> StdBrain::param $mybrain UseRandom
00375     true
00376   \endcode
00377 
00378   Now, we can also change its UseRandom value
00379 
00380   \code
00381     ./bin/invt 14>>> StdBrain::param $mybrain UseRandom 0
00382     1
00383   \endcode
00384 
00385   (Note that the '1' returned here is the 'bool' value indicating
00386   whether a param named 'UseRandom' was found). Now let's re-query and
00387   see that our change took effect:
00388 
00389   \code
00390     ./bin/invt 15>>> StdBrain::param $mybrain UseRandom
00391     false
00392   \endcode
00393 
00394   OK, its value is now 'false'. Now let's try to give a bogus param
00395   value:
00396 
00397   \code
00398     ./bin/invt 16>>> StdBrain::param $mybrain UseRandom 3
00399     StringConversions::convertFromString: Bogus format: 3 -- IGNORED
00400     1
00401   \endcode
00402 
00403   Let's make a "typo" and query a non-existent param:
00404 
00405   \code
00406     ./bin/invt 16>>> StdBrain::param $mybrain nosuchparam
00407     [Brain]::getModelParamString: No parameter named 'nosuchparam' -- IGNORING
00408     <unknown>
00409   \endcode
00410 
00411   We can use the "?" function to get usage information about a command:
00412 
00413   \code
00414     ./bin/invt 18>>> ? Brain::param
00415     Brain::param resolves to ::ModelComponent::param
00416             ::ModelComponent::param objref paramname (argc=[3..3])
00417             ::ModelComponent::param objref paramname paramvalue (argc=[4..4])
00418             (defined at src/Script/ModelScript.C:118)
00419   \endcode
00420 
00421   Here we see that Brain::param has two overloads, one that returns
00422   the current value, and one that sets a new value. The proper
00423   overload is selected at runtime based on the argument count.
00424 
00425   We can apply "?" to itself:
00426 
00427   \code
00428     ./bin/invt 18>>> ? ?
00429     ? resolves to ::?
00430             ::? cmd_name (argc=[2..2])
00431             (defined at src/tcl/tclpkg-misc.cc:156)
00432   \endcode
00433 
00434   We can use "?" to see (1) which package originated the command, and
00435   (2) where it is defined. Here we see that Brain has inherited
00436   subCompByName from ModelComponent, and that it is defined in
00437   src/Script/ModelScript.C:
00438 
00439   \code
00440     ./bin/invt 19>>> ? Brain::subCompByName
00441     Brain::subCompByName resolves to ::ModelComponent::subCompByName
00442             ::ModelComponent::subCompByName objref tagname (argc=[3..3])
00443             (defined at src/Script/ModelScript.C:108)
00444   \endcode
00445 
00446   We can query if an object is a (subclass of) a particular type:
00447 
00448   \code
00449     ./bin/invt 17>>> ModelComponent::is $mybrain
00450     1
00451 
00452     ./bin/invt 18>>> StdBrain::is $mm
00453     0
00454   \endcode
00455 
00456   Try to get modules out of Brain:
00457 
00458   \code
00459     ./bin/invt 20>>> StdBrain::module $mybrain Retina
00460     0
00461     ./bin/invt 21>>> StdBrain::module $mybrain VisualCortex
00462     0
00463   \endcode
00464 
00465   OK, those returned null objects because the brain hasn't been
00466   start()ed yet.
00467 
00468   Now let's try to get a invalid module type (note that this is an
00469   example of what happens with an LFATAL, which throws an exception,
00470   which is caught and reported to the script interpreter):
00471 
00472   \code
00473     ./bin/invt 22>>> StdBrain::module $mybrain Frobnaz
00474     Brain::module: Invalid module type Frobnaz -- ABORT
00475     -- ABORT.
00476     exception of unknown type caught at src/tcl/commandgroup.cc:442:
00477     StdBrain::module:
00478 
00479     ./bin/invt 23>>> StdBrain::hasModule $mybrain Frobnaz
00480     Brain::hasModule: Invalid module type Frobnaz -- ABORT
00481     -- ABORT.
00482     exception of unknown type caught at src/tcl/commandgroup.cc:442:
00483     StdBrain::hasModule:
00484   \endcode
00485 
00486   Play around with our ModelManager some more:
00487 
00488   \code
00489     ./bin/invt 25>>> ModelManager::numSubComp $mm
00490     0
00491     ./bin/invt 26>>> ModelManager::tagName $mm
00492     model
00493     ./bin/invt 27>>> ModelManager::descriptiveName $mm
00494     iLab Neuromorphic Vision Toolit
00495   \endcode
00496 
00497   Add our StdBrain to the ModelManager:
00498 
00499   \code
00500     ./bin/invt 28>>> ModelManager::addSubComponent $mm $mybrain
00501     0
00502   \endcode
00503 
00504   and now see how many subcomponents it has (you can use up-arrow to
00505   retrieve the identical call that we did 3 or 4 steps back):
00506 
00507   \code
00508     ./bin/invt 29>>> ModelManager::numSubComp $mm
00509     1
00510   \endcode
00511 
00512   Get the StdBrain back out of the ModelManager:
00513 
00514   \code
00515     ./bin/invt 31>>> ModelManager::subCompByIndex $mm 0
00516     2
00517   \endcode
00518 
00519   Try to get an out-of-bounds subcomponent:
00520 
00521   \code
00522     ./bin/invt 32>>> ModelManager::subCompByIndex $mm 123
00523     [iLab Neuromorphic Vision Toolit]::subComponent:
00524         iLab Neuromorphic Vision Toolit: request for
00525         subcomponent 123 but I have only 1 -- FATAL
00526     -- ABORT.
00527     exception of unknown type caught at src/tcl/commandgroup.cc:442:
00528     ModelManager::subCompByIndex:
00529   \endcode
00530 
00531   See what's in the model manager now:
00532 
00533   \code
00534     ./bin/invt 33>>> ModelManager::printout $mm
00535     model: ShowHelpMessage = true
00536     model: DebugMode = false
00537     model: UsingFPE = false
00538     model: TestMode = false
00539     model: TextLogFile =
00540     model: LoadConfigFile =
00541     model: SaveConfigFile =
00542     model.Brain: IORtype = Auto
00543     model.Brain: UseRandom = false
00544     model.Brain: FOAradius = -1
00545     model.Brain: FoveaRadius = -1
00546     model.Brain: SimulationTimeStep = 0.0001
00547     model.Brain: LevelSpec = 0-0,0-0,0
00548     model.Brain: BrainBoringDelayInMs = 200
00549     model.Brain: BrainBoringSMmv = 3
00550     model.Brain: BrainMaxWinMv = 5
00551     model.Brain: BlankBlink = false
00552     model.Brain: BrainSaveObjMask = false
00553     model.Brain: BrainTooManyShifts = 0
00554     model.Brain: BrainTooMuchTime = 0
00555     model.Brain: BrainSaveWinnerFeatures = false
00556     model.Brain.ShapeEstimator: ShapeEstimatorMode = FeatureMap
00557     model.Brain.ShapeEstimator: ShapeEstimatorSmoothMethod = Gaussian
00558     model.Brain.RetinaConfigurator: RetinaType = Std
00559     model.Brain.SaccadeControllerConfigurator: SaccadeControllerType = None
00560     model.Brain.VisualCortexConfigurator: VisualCortexType = None
00561     model.Brain.SaliencyMapConfigurator: SaliencyMapType = None
00562     model.Brain.TaskRelevanceMapConfigurator: TaskRelevanceMapType = None
00563     model.Brain.AttentionGuidanceMapConfigurator: AttentionGuidanceMapType = None
00564     model.Brain.WinnerTakeAllConfigurator: WinnerTakeAllType = None
00565     model.Brain.SimulationViewerConfigurator: SimulationViewerType = None
00566     model.Brain.InferoTemporalConfigurator: InferoTemporalType = None
00567     model.Brain.GistEstimatorConfigurator: GistEstimatorType = None
00568   \endcode
00569 
00570   change the ModelManager's tag name:
00571 
00572   \code
00573     ./bin/invt 34>>> ModelManager::tagName $mm "someOtherName"
00574     ./bin/invt 35>>> ModelManager::tagName $mm
00575     someOtherName
00576   \endcode
00577 
00578   Now, after all that, here's a shorthand syntax. For objects that
00579   have a tcl package, we can use "-> $obj cmdname" as shorthand for
00580   "<type>::cmdname $obj", where <type> is whatever is returned from
00581   "Obj::type $obj".
00582 
00583   That is, "-> $mm printout " is equivalent to "ModelManager::printout
00584   $mm", because [Obj::type $mm] is "ModelManager":
00585 
00586   \code
00587     ./bin/invt 36>>> -> $mm tagName
00588     someOtherName
00589     ./bin/invt 37>>> -> $mm tagName "someNewName"
00590     someOtherName
00591     ./bin/invt 36>>> -> $mm tagName
00592     someNewName
00593   \endcode
00594 
00595   Finally, when we're done:
00596 
00597   \code
00598     ./bin/invt 39>>> exit
00599   \endcode
00600 
00601   After we exit the interpreter, it leaves behind a prof.out file
00602   showing (1) average microseconds per call, (2) number of calls, (3)
00603   self microseconds, and (4) self+child microseconds, for each of the
00604   script commands (do "sort -n +2 prof.out | tail -20") to sort by
00605   total self microseconds. Here's one example left behind after
00606   running tests/test_scriptvision_blackbox.tcl, showing that
00607   Brain::evolve was called 1799 times, most of the time was spent in 6
00608   calls to Brain::input, etc.
00609 
00610   \code
00611     $ sort -n +2 prof.out | tail -20
00612            291      1        291        291 tcl/ModelManager::extraArgs
00613            123      3        369        369 tcl/ModelComponent::addSubComponent
00614            242      2        484        484 tcl/FrameSeries::fileStem
00615            246      2        492        492 tcl/Image::byte
00616           1281      1       1281       1281 tcl/ModelManager::find_all
00617           3843      8       1741      30745 tcl/::->
00618            689      6       4139       4139 tcl/InputFrameSeries::readRGB
00619           1955      3       5866       5866 tcl/Obj::new
00620           5986      1       5986       5986 tcl/ModelComponent::start
00621           1346      6       8080       8080 tcl/Brain::saveResults
00622              6   1794      12075      12075 tcl/FrameSeries::isMultiframe
00623          21874      1      21874      21874 tcl/ModelManager::parseCommandLine
00624              6   3598      23255      23255 tcl/FrameSeries::didDisplayFrames
00625              7   3599      27831      27831 tcl/FrameSeries::update
00626             49   1799      88937      88937 tcl/Brain::evolve
00627         162231      6     973388     973388 tcl/Brain::input
00628   \endcode
00629 
00630 */
Generated on Sun May 8 08:04:09 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3