FunctionGraph.cpp

00001 /***************************************************************************
00002   tag: Peter Soetens  Tue Dec 21 22:43:07 CET 2004  FunctionGraph.cxx 
00003 
00004                         FunctionGraph.cxx -  description
00005                            -------------------
00006     begin                : Tue December 21 2004
00007     copyright            : (C) 2004 Peter Soetens
00008     email                : peter.soetens@mech.kuleuven.ac.be
00009  
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037  
00038  
00039 #include "FunctionGraph.hpp"
00040 #include "GraphCopier.hpp"
00041 #include "AttributeBase.hpp"
00042 #include "scripting/ProgramTask.hpp"
00043 #include "ProgramProcessor.hpp"
00044 #include "TaskObject.hpp"
00045 
00046 #include "CommandNOP.hpp"
00047 #include "ConditionFalse.hpp"
00048 #include "ConditionTrue.hpp"
00049 #include <boost/graph/copy.hpp>
00050 #include <utility>
00051 
00052 namespace RTT
00053 {
00054     using namespace boost;
00055     using namespace std;
00056     
00057     
00058 
00059     FunctionGraph::FunctionGraph(const std::string& _name)
00060         : myName(_name), pausing(false), mstep(false), context(0)
00061     {
00062         // the start vertex of our function graph
00063         startv = add_vertex( program );
00064         put(vertex_exec, program, startv, VertexNode::normal_node );
00065         exitv = add_vertex( program );
00066         put(vertex_exec, program, exitv, VertexNode::normal_node);
00067     }
00068 
00069     FunctionGraph::FunctionGraph( const FunctionGraph& orig )
00070         :  program( orig.getGraph() ), myName( orig.getName() )
00071     {
00072         // The nodes are copied, which causes a clone of their contents.
00073         graph_traits<Graph>::vertex_iterator v1,v2, it;
00074         tie(v1,v2) = vertices(program);
00075         for ( it=v1; it != v2; ++it)
00076             if ( get( vertex_exec, program, *it) == VertexNode::func_start_node )
00077                 break;
00078         startv = *v1;
00079         for ( it=v1; it != v2; ++it)
00080             if ( get( vertex_exec, program, *it) == VertexNode::func_exit_node )
00081                 break;
00082         exitv = *v1;
00083 
00084         // Copy-clone over the TAB pointers.
00085         std::vector<AttributeBase*> argsvect = orig.getArguments();
00086         std::vector<AttributeBase*>::iterator ita = argsvect.begin();
00087         for ( ; ita != argsvect.end(); ++ita)
00088             this->args.push_back( (*ita)->clone() );
00089         this->finish();
00090     }
00091 
00092     void FunctionGraph::finish()
00093     {
00094         put(vertex_exec, program, startv, VertexNode::func_start_node );
00095         put(vertex_exec, program, exitv, VertexNode::func_exit_node);
00096 
00097         // Because we use listS, we need to re-index the map :-(
00098         // If we do not do this, it can not be copied by the copy_graph
00099         // function.
00100         property_map<Graph, vertex_index_t>::type
00101             index = get(vertex_index, program);
00102 
00103         // initialize the vertex_index property values
00104         // so that it can be copied into other graphs.
00105         graph_traits<Graph>::vertex_iterator vi, vend;
00106         graph_traits<Graph>::vertices_size_type cnt = 0;
00107         for(tie(vi,vend) = vertices(program); vi != vend; ++vi)
00108             put(index, *vi, cnt++);
00109         this->reset();
00110     }
00111 
00112     FunctionGraph::~FunctionGraph()
00113     {
00114         std::vector<AttributeBase*>::iterator it = args.begin();
00115         for ( ; it != args.end(); ++it)
00116             delete *it;
00117         pStatus = Status::unloaded;
00118         this->handleUnload();
00119     }
00120 
00121     void FunctionGraph::setProgramTask(TaskObject* mytask)
00122     {
00123         context = mytask;
00124     }
00125 
00126     void FunctionGraph::handleUnload()
00127     {
00128         if (context == 0)
00129             return;
00130         // just kill off the interface.
00131         if (context->getParent() ) {
00132             context->getParent()->removeObject(context->getName());
00133         } else {
00134             // no parent, delete it ourselves.
00135             delete context;
00136         }
00137 
00138         context = 0;
00139     }
00140 
00141 
00142     bool FunctionGraph::start()
00143     {
00144         if ( !pp || !pp->getActivity() || !pp->getActivity()->isActive() )
00145             return false;
00146         if ( pStatus == Status::stopped || pStatus == Status::paused) {
00147             pStatus = Status::running;
00148             return true;
00149         }
00150         return false;
00151     }
00152 
00153     bool FunctionGraph::pause()
00154     {
00155         if ( pp ) {
00156             pausing = true;
00157             return true;
00158         }
00159         return false;
00160     }
00161 
00162     bool FunctionGraph::step()
00163     {
00164         if ( pp && (pStatus == Status::paused) && mstep == false) {
00165             mstep = true;
00166             return true;
00167         }
00168         return false;
00169     }
00170 
00171     bool FunctionGraph::stepDone() const
00172     {
00173         return mstep == false;
00174     }
00175 
00176     bool FunctionGraph::execute()
00177     {
00178         if (pausing) {
00179             pStatus = Status::paused;
00180             pausing = false;
00181             return true;
00182         }
00183         switch (pStatus) {
00184         case Status::running:
00185             return this->executeUntil();
00186             break;
00187         case Status::paused:
00188             if (mstep) {
00189                 mstep = false;
00190                 return this->executeStep();
00191             } else
00192                 return true;
00193             break;
00194         case Status::error:
00195         case Status::unloaded:
00196             return false;
00197             break;
00198         case Status::stopped:
00199             return true;
00200             break;
00201         }
00202         return false;
00203     }
00204             
00205 
00206     bool FunctionGraph::executeUntil()
00207     {
00208         graph_traits<Graph>::out_edge_iterator ei, ei_end;
00209         // the map contains _references_ to all vertex_command properties
00210         boost::property_map<Graph, vertex_command_t>::type
00211             cmap = get(vertex_command, program);
00212         boost::property_map<Graph, edge_condition_t>::type
00213             emap = get(edge_condition, program);
00214 
00215         do {
00216             // Check this always on entry of executeUntil :
00217             // initialise current node if needed and reset all its out_edges
00218             // if previous == current, we DO NOT RESET, because we want to check
00219             // if previous command has completed !
00220             if ( previous != current )
00221                 {
00222                     for ( tie(ei, ei_end) = boost::out_edges( current, program ); ei != ei_end; ++ei)
00223                         emap[*ei].reset();
00224                     cmap[current].startExecution();
00225                 }
00226 
00227             // initial conditions :
00228             previous = current;
00229             // execute the current command.
00230             if ( !cmap[current].execute() ) {
00231                 pStatus = Status::error;
00232                 return false;
00233             }
00234         
00235             // Branch selecting Logic :
00236             if ( cmap[current].isValid() ) {
00237                 for ( tie(ei, ei_end) = boost::out_edges( current, program ); ei != ei_end; ++ei) {
00238                     if ( emap[*ei].evaluate() ) {
00239                         current = boost::target(*ei, program);
00240                         // a new node has been found ...
00241                         // so continue
00242                         break; // exit from for loop.
00243                     }
00244                 }
00245             }
00246         } while ( previous != current && pStatus == Status::running && !pausing); // keep going if we found a new node
00247 
00248         // check finished state
00249         if (current == exitv)
00250             this->stop();
00251         return true; // we need to wait.
00252     }
00253 
00254     bool FunctionGraph::executeStep()
00255     {
00256         graph_traits<Graph>::out_edge_iterator ei, ei_end;
00257         // the map contains _references_ to all vertex_command properties
00258         boost::property_map<Graph, vertex_command_t>::type
00259             cmap = get(vertex_command, program);
00260         boost::property_map<Graph, edge_condition_t>::type
00261             emap = get(edge_condition, program);
00262 
00263         // initialise current node if needed and reset all its out_edges
00264         if ( previous != current )
00265         {
00266             for ( tie(ei, ei_end) = boost::out_edges( current, program ); ei != ei_end; ++ei)
00267                 emap[*ei].reset();
00268             cmap[current].startExecution();
00269             previous = current;
00270         }
00271 
00272         // execute the current command.
00273         if ( !cmap[current].execute() ) {
00274             pStatus = Status::error;
00275             return false;
00276         }
00277 
00278         // Branch selecting Logic :
00279         if ( cmap[current].isValid() ) {
00280             for ( tie(ei, ei_end) = boost::out_edges( current, program ); ei != ei_end; ++ei) {
00281                 if ( emap[*ei].evaluate() ) {
00282                     current = boost::target(*ei, program);
00283                     if (current == exitv)
00284                         this->stop();
00285                     // a new node has been found ...
00286                     // it will be executed in the next step.
00287                     return true;
00288                 }
00289             }
00290         }
00291         // check finished state
00292         if (current == exitv)
00293             this->stop();
00294         return true; // no new branch found yet !
00295     }
00296 
00297     void FunctionGraph::reset() {
00298         this->stop();
00299     }
00300 
00301     bool FunctionGraph::stop()
00302     {
00303         // stop even works if no pp is present
00304         current = startv;
00305         previous = exitv;
00306         pStatus = Status::stopped;
00307         return true;
00308     }
00309 
00310     const std::string& FunctionGraph::getName() const
00311     {
00312         return myName;
00313     }
00314 
00315     void FunctionGraph::setName(const std::string& name)
00316     {
00317         myName = name;
00318     }
00319 
00320     std::string FunctionGraph::getText() const
00321     {
00322         return _text;
00323     }
00324 
00325     void FunctionGraph::setText(const std::string& text)
00326     {
00327         _text = text;
00328     }
00329 
00330     int FunctionGraph::getLineNumber() const
00331     {
00332         return get(vertex_command, program)[current].getLineNumber();
00333     }
00334 
00335     FunctionGraph* FunctionGraph::copy( std::map<const DataSourceBase*, DataSourceBase*>& replacementdss ) const
00336     {
00337         typedef boost::property_map<Graph, vertex_index_t>::const_type indexmap_t;
00338         typedef boost::graph_traits<Graph>::vertex_descriptor vd_t;
00339         typedef std::vector<vd_t> o2cvect_t;
00340         typedef boost::iterator_property_map<o2cvect_t::iterator, indexmap_t, vd_t, vd_t&> o2cmap_t;
00341         FunctionGraph* ret = new FunctionGraph( getName() );
00342 
00343         // clear out unneccessary vertices ( we will copy new ones below )
00344         remove_vertex( ret->startv, ret->program );
00345         remove_vertex( ret->exitv, ret->program );
00346 
00347         indexmap_t indexmap = get( vertex_index, program );
00348         // here we assume that the indexing of program is set properly...
00349         o2cvect_t o2cvect( num_vertices( program ) );
00350         o2cmap_t o2cmap( o2cvect.begin(), indexmap );
00351 
00352 //         std::cerr << "Start copy of " <<std::endl;
00353 //         this->debugPrintout();
00354 //         std::cerr << "Empty ret: " <<std::endl;
00355 //         ret->debugPrintout();
00356         // The replacementdss map contains mappings from this->datasource to copy->datasource, 
00357         // thus we can rebuild a vector<AttributeBase*>, which will be automagically be
00358         // found by copy_graph.
00359         // func args are never instantiated, so that we can keep making copies.
00360         for (unsigned int i=0; i < args.size(); ++i)
00361             ret->addArgument( args[i]->copy( replacementdss, false ) ); 
00362 
00363         boost::copy_graph( program, ret->program,
00364                            boost::vertex_copy( GraphVertexCopier( program, ret->program, replacementdss ) ).
00365                            edge_copy( GraphEdgeCopier( program, ret->program, replacementdss ) ).
00366                            orig_to_copy( o2cmap ) );
00367 
00368         ret->startv = o2cmap[startv];
00369         ret->exitv = o2cmap[exitv];
00370         ret->current = o2cmap[current];
00371         ret->previous = o2cmap[previous];
00372 
00373         // so that ret itself can be copied again :
00374         ret->finish();
00375 
00376         // copy progproc state also
00377         if (this->pp)
00378             ret->setProgramProcessor(pp);
00379 //         std::cerr << "Resulted in :" <<std::endl;
00380 //         ret->debugPrintout();
00381 
00382         return ret;
00383     }
00384 
00385     FunctionGraph* FunctionGraph::clone() const
00386     {
00387         return new FunctionGraph(*this);
00388     }
00389 
00390     void FunctionGraph::debugPrintout() const {
00391 #if 0
00392         graph_traits<Graph>::vertex_iterator v,vend;
00393         tie(v,vend) = vertices(program);
00394         boost::property_map<Graph, vertex_command_t>::const_type
00395             cmap = get(vertex_command, program);
00396         boost::property_map<Graph, vertex_index_t>::const_type
00397             imap = get(vertex_index, program);
00398         std::cerr << "program " << getName() << std::endl;
00399         std::cerr << " number of vertices: " << boost::num_vertices(program) << std::endl;
00400         for ( ; v != vend; ++v )
00401         {
00402             int index = get( imap, *v );
00403             CommandInterface* cmd = get( cmap, *v ).getCommand();
00404             if ( cmd )
00405                 std::cerr << " " << index << " " << typeid( *cmd ).name() << std::endl;
00406             else
00407                 std::cerr << " " << index << " (null)" << std::endl;
00408         }
00409 #endif
00410     }
00411 
00412     void FunctionGraph::clearArguments() {
00413         for (std::vector<AttributeBase*>::iterator it = args.begin(); it != args.end(); ++it)
00414             delete *it;
00415         args.clear();
00416     }
00417 
00418 }
00419 

Generated on Tue Mar 25 17:41:46 2008 for OrocosReal-TimeToolkit by  doxygen 1.5.3