adevs
/home/rotten/Code/adevs/trunk/include/adevs_simulator.h
00001 /***************
00002 Copyright (C) 2000-2010 by James Nutaro
00003 
00004 This library is free software; you can redistribute it and/or
00005 modify it under the terms of the GNU Lesser General Public
00006 License as published by the Free Software Foundation; either
00007 version 2 of the License, or (at your option) any later version.
00008 
00009 This library is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public
00015 License along with this library; if not, write to the Free Software
00016 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 Bugs, comments, and questions can be sent to nutaro@gmail.com
00019 ***************/
00020 #ifndef __adevs_simulator_h_
00021 #define __adevs_simulator_h_
00022 #include "adevs_abstract_simulator.h"
00023 #include "adevs_models.h"
00024 #include "adevs_event_listener.h"
00025 #include "adevs_sched.h"
00026 #include "adevs_bag.h"
00027 #include "adevs_set.h"
00028 #include "object_pool.h"
00029 #include "adevs_lp.h"
00030 #include <cassert>
00031 #include <cstdlib>
00032 #include <iostream>
00033 #include <vector>
00034 
00035 namespace adevs
00036 {
00037 
00044 template <class X> class Simulator:
00045         public AbstractSimulator<X>
00046 {
00047         public:
00054                 Simulator(Devs<X>* model):
00055                         AbstractSimulator<X>(),lps(NULL)
00056                 {
00057                         schedule(model,0.0);
00058                 }
00063                 double nextEventTime()
00064                 {
00065                         return sched.minPriority();
00066                 }
00068                 void execNextEvent()
00069                 {
00070                         computeNextOutput();
00071                         computeNextState(bogus_input,sched.minPriority());
00072                 }
00074                 void execUntil(double tend)
00075                 {
00076                         while (nextEventTime() <= tend && nextEventTime() < DBL_MAX)
00077                                 execNextEvent();
00078                 }
00084                 void computeNextOutput();
00093                 void computeNextState(Bag<Event<X> >& input, double t);
00099                 ~Simulator();
00104                 void addModel(Atomic<X>* model) 
00105                 {
00106                         schedule(model,0.0);
00107                 }
00112                 Simulator(LogicalProcess<X>* lp);
00124                 void beginLookahead();
00129                 void endLookahead();
00136                 void lookNextEvent();
00137         private:
00138                 typedef enum { OUTPUT_OK, OUTPUT_NOT_OK, RESTORING_OUTPUT } OutputStatus;
00139                 // Structure to support parallel computing by a logical process
00140                 struct lp_support
00141                 {
00142                         // The processor that this simulator works for
00143                         LogicalProcess<X>* lp;
00144                         bool look_ahead, stop_forced;
00145                         OutputStatus out_flag;
00146                         Bag<Atomic<X>*> to_restore;
00147                 };
00148                 // This is NULL if the simulator is not supporting a logical process
00149                 lp_support* lps;
00150                 // Bogus input bag for execNextEvent() method
00151                 Bag<Event<X> > bogus_input;
00152                 // The event schedule
00153                 Schedule<X> sched;
00154                 // List of imminent models
00155                 Bag<Atomic<X>*> imm;
00156                 // List of models activated by input
00157                 Bag<Atomic<X>*> activated;
00158                 // Pools of preallocated, commonly used objects
00159                 object_pool<Bag<X> > io_pool;
00160                 object_pool<Bag<Event<X> > > recv_pool;
00161                 // Sets for computing structure changes.
00162                 Bag<Devs<X>*> added;
00163                 Bag<Devs<X>*> removed;
00164                 Set<Devs<X>*> next;
00165                 Set<Devs<X>*> prev;
00166                 // Model transition functions are evaluated from the bottom up!
00167                 struct bottom_to_top_depth_compare
00168                 {
00169                         bool operator()(const Network<X>* m1, const Network<X>* m2) const
00170                         {
00171                                 unsigned long int d1 = 0, d2 = 0;
00172                                 // Compute depth of m1
00173                                 const Network<X>* m = m1->getParent();
00174                                 while (m != NULL) 
00175                                 {
00176                                         d1++;
00177                                         m = m->getParent();
00178                                 }
00179                                 // Compute depth of m2
00180                                 m = m2->getParent();
00181                                 while (m != NULL)
00182                                 {
00183                                         d2++;
00184                                         m = m->getParent();
00185                                 }
00186                                 // Models at the same depth are sorted by name
00187                                 if (d1 == d2) return m1 < m2;
00188                                 // Otherwise, sort by depth
00189                                 return d1 > d2;
00190                         }
00191                 };
00192                 struct top_to_bottom_depth_compare
00193                 {
00194                         bool operator()(const Devs<X>* m1, const Devs<X>* m2) const
00195                         {
00196                                 unsigned long int d1 = 0, d2 = 0;
00197                                 // Compute depth of m1
00198                                 const Network<X>* m = m1->getParent();
00199                                 while (m != NULL) 
00200                                 {
00201                                         d1++;
00202                                         m = m->getParent();
00203                                 }
00204                                 // Compute depth of m2
00205                                 m = m2->getParent();
00206                                 while (m != NULL)
00207                                 {
00208                                         d2++;
00209                                         m = m->getParent();
00210                                 }
00211                                 // Models at the same depth are sorted by name
00212                                 if (d1 == d2) return m1 < m2;
00213                                 // Otherwise, sort by depth
00214                                 return d1 < d2;
00215                         }
00216                 };
00217                 std::set<Network<X>*,bottom_to_top_depth_compare> model_func_eval_set;
00218                 std::set<Devs<X>*,top_to_bottom_depth_compare> sorted_removed;
00223                 void schedule(Devs<X>* model, double t);
00225                 void route(Network<X>* parent, Devs<X>* src, X& x);
00231                 void inject_event(Atomic<X>* model, X& value);
00236                 void unschedule_model(Devs<X>* model);
00242                 void clean_up(Devs<X>* model);
00249                 void exec_event(Atomic<X>* model, bool internal, double t);
00253                 void getAllChildren(Network<X>* model, Set<Devs<X>*>& s);
00259                 bool manage_lookahead_data(Atomic<X>* model);
00260 };
00261 
00262 template <class X>
00263 void Simulator<X>::computeNextOutput()
00264 {
00265         // If the imminent set is up to date, then just return
00266         if (imm.empty() == false) return;
00267         // Get the imminent models from the schedule. This sets the active flags.
00268         sched.getImminent(imm);
00269         // Compute output functions and route the events. The bags of output
00270         // are held for garbage collection at a later time.
00271         for (typename Bag<Atomic<X>*>::iterator imm_iter = imm.begin(); 
00272                 imm_iter != imm.end(); imm_iter++)
00273         {
00274                 Atomic<X>* model = *imm_iter;
00275                 // If the output for this model has already been computed, then skip it
00276                 if (model->y == NULL)
00277                 {
00278                         model->y = io_pool.make_obj();
00279                         model->output_func(*(model->y));
00280                         // Route each event in y
00281                         for (typename Bag<X>::iterator y_iter = model->y->begin(); 
00282                         y_iter != model->y->end(); y_iter++)
00283                         {
00284                                 route(model->getParent(),model,*y_iter);
00285                         }
00286                 }
00287         }
00288 }
00289 
00290 template <class X>
00291 void Simulator<X>::computeNextState(Bag<Event<X> >& input, double t)
00292 {
00293         // Clean up if there was a previous IO calculation
00294         if (t < sched.minPriority())
00295         {
00296                 typename Bag<Atomic<X>*>::iterator iter;
00297                 for (iter = activated.begin(); iter != activated.end(); iter++)
00298                 {
00299                         clean_up(*iter);
00300                 }
00301                 activated.clear();
00302                 for (iter = imm.begin(); iter != imm.end(); iter++)
00303                 {
00304                         clean_up(*iter);
00305                 }
00306                 imm.clear();
00307         }
00308         // Otherwise, if the internal IO needs to be computed, do it
00309         else if (t == sched.minPriority() && imm.empty())
00310         {
00311                 computeNextOutput();
00312         }
00313         // Apply the injected inputs
00314         for (typename Bag<Event<X> >::iterator iter = input.begin(); 
00315         iter != input.end(); iter++)
00316         {
00317                 Atomic<X>* amodel = (*iter).model->typeIsAtomic();
00318                 if (amodel != NULL)
00319                 {
00320                         inject_event(amodel,(*iter).value);
00321                 }
00322                 else
00323                 {
00324                         route((*iter).model->typeIsNetwork(),(*iter).model,(*iter).value);
00325                 }
00326         }
00327         /*
00328         Compute the states of atomic models.  Store Network models that 
00329         need to have their model transition function evaluated in a
00330         special container that will be used when the structure changes are
00331         computed (see exec_event(.)).
00332         */
00333         for (typename Bag<Atomic<X>*>::iterator iter = imm.begin(); 
00334         iter != imm.end(); iter++)
00335         {
00336                 exec_event(*iter,true,t); // Internal and confluent transitions
00337         }
00338         for (typename Bag<Atomic<X>*>::iterator iter = activated.begin(); 
00339         iter != activated.end(); iter++)
00340         {
00341                 exec_event(*iter,false,t); // External transitions
00342         }
00349         if (model_func_eval_set.empty() == false)
00350         {
00351                 while (!model_func_eval_set.empty())
00352                 {
00353                         Network<X>* network_model = *(model_func_eval_set.begin());
00354                         getAllChildren(network_model,prev);
00355                         if (network_model->model_transition() &&
00356                                         network_model->getParent() != NULL)
00357                         {
00358                                 model_func_eval_set.insert(network_model->getParent());
00359                         }
00360                         getAllChildren(network_model,next);
00361                         model_func_eval_set.erase(network_model);
00362                 }
00363                 // Find the set of models that were added.
00364                 set_assign_diff(added,next,prev);
00365                 // Find the set of models that were removed
00366                 set_assign_diff(removed,prev,next);
00367                 // Intersection of added and removed is always empty, so no need to look
00368                 // for models in both (an earlier version of the code did this).
00369                 next.clear();
00370                 prev.clear();
00377                 for (typename Bag<Devs<X>*>::iterator iter = added.begin(); 
00378                         iter != added.end(); iter++)
00379                 {
00380                         schedule(*iter,t);
00381                 }
00382                 // Done with the additions
00383                 added.clear();
00384                 // Remove the models that are in the removed set.
00385                 for (typename Bag<Devs<X>*>::iterator iter = removed.begin(); 
00386                         iter != removed.end(); iter++)
00387                 {
00388                         clean_up(*iter);
00389                         unschedule_model(*iter);
00390                         // Add to a sorted remove set for deletion
00391                         sorted_removed.insert(*iter); 
00392                 }
00393                 // Done with the unsorted remove set
00394                 removed.clear();
00395                 // Delete the sorted removed models
00396                 while (!sorted_removed.empty())
00397                 {
00398                         // Get the model to erase
00399                         Devs<X>* model_to_remove = *(sorted_removed.begin());
00404                         if (model_to_remove->typeIsNetwork() != NULL)
00405                         {
00406                                 getAllChildren(model_to_remove->typeIsNetwork(),prev);
00407                                 for (typename Set<Devs<X>*>::iterator iter = prev.begin(); 
00408                                         iter != prev.end(); iter++)
00409                                 {
00410                                         sorted_removed.erase(*iter);
00411                                 }
00412                                 prev.clear();
00413                         }
00414                         // Remove the model
00415                         sorted_removed.erase(sorted_removed.begin());
00416                         // Delete the model and its children
00417                         delete model_to_remove;
00418                 }
00419                 // Removed sets should be empty now
00420                 assert(prev.empty());
00421                 assert(sorted_removed.empty());
00422         } // End of the structure change
00423         // Cleanup and reschedule models that changed state in this iteration
00424         // and survived the structure change phase.
00425         for (typename Bag<Atomic<X>*>::iterator iter = imm.begin(); 
00426                 iter != imm.end(); iter++) // Schedule the imminents
00427         {
00428                 clean_up(*iter);
00429                 schedule(*iter,t);
00430         }
00431         // Schedule the activated
00432         for (typename Bag<Atomic<X>*>::iterator iter = activated.begin(); 
00433                 iter != activated.end(); iter++)
00434         {
00435                 clean_up(*iter);
00436                 schedule(*iter,t);
00437         }
00438         // Empty the bags
00439         imm.clear();
00440         activated.clear();
00441         // If we are looking ahead, throw an exception if a stop was forced
00442         if (lps != NULL && lps->stop_forced)
00443         {
00444                 lookahead_impossible_exception err;
00445                 throw err;
00446         }
00447 }
00448 
00449 template <class X>
00450 void Simulator<X>::clean_up(Devs<X>* model)
00451 {
00452         Atomic<X>* amodel = model->typeIsAtomic();
00453         if (amodel != NULL)
00454         {
00455                 amodel->active = false;
00456                 if (amodel->x != NULL)
00457                 {
00458                         amodel->x->clear();
00459                         io_pool.destroy_obj(amodel->x);
00460                         amodel->x = NULL;
00461                 }
00462                 if (amodel->y != NULL)
00463                 {
00464                         amodel->gc_output(*(amodel->y));
00465                         amodel->y->clear();
00466                         io_pool.destroy_obj(amodel->y);
00467                         amodel->y = NULL;
00468                 }
00469         }
00470         else
00471         {
00472                 Set<Devs<X>*> components;
00473                 model->typeIsNetwork()->getComponents(components);
00474                 for (typename Set<Devs<X>*>::iterator iter = components.begin();
00475                 iter != components.end(); iter++)
00476                 {
00477                         clean_up(*iter);
00478                 }
00479         }
00480 }
00481 
00482 template <class X>
00483 void Simulator<X>::unschedule_model(Devs<X>* model)
00484 {
00485         if (model->typeIsAtomic() != NULL)
00486         {
00487                 sched.schedule(model->typeIsAtomic(),DBL_MAX);
00488                 imm.erase(model->typeIsAtomic());
00489                 activated.erase(model->typeIsAtomic());
00490         }
00491         else
00492         {
00493                 Set<Devs<X>*> components;
00494                 model->typeIsNetwork()->getComponents(components);
00495                 for (typename Set<Devs<X>*>::iterator iter = components.begin();
00496                 iter != components.end(); iter++)
00497                 {
00498                         unschedule_model(*iter);
00499                 }
00500         }
00501 }
00502 
00503 template <class X>
00504 void Simulator<X>::schedule(Devs<X>* model, double t)
00505 {
00506         Atomic<X>* a = model->typeIsAtomic();
00507         if (a != NULL)
00508         {
00509                 a->tL = t;
00510                 double dt = a->ta();
00511                 if (dt < 0.0)
00512                 {
00513                         exception err("Negative time advance",a);
00514                         throw err;
00515                 }
00516                 if (dt == DBL_MAX)
00517                         sched.schedule(a,DBL_MAX);
00518                 else
00519                         sched.schedule(a,t+dt);
00520         }
00521         else
00522         {
00523                 Set<Devs<X>*> components;
00524                 model->typeIsNetwork()->getComponents(components);
00525                 typename Set<Devs<X>*>::iterator iter = components.begin();
00526                 for (; iter != components.end(); iter++)
00527                 {
00528                         schedule(*iter,t);
00529                 }
00530         }
00531 }
00532 
00533 template <class X>
00534 void Simulator<X>::inject_event(Atomic<X>* model, X& value)
00535 {
00536         if (model->active == false)
00537         {
00538                 model->active = true;
00539                 activated.insert(model);
00540         }
00541         if (model->x == NULL)
00542         {
00543                 model->x = io_pool.make_obj();
00544         }
00545         model->x->insert(value);
00546 }
00547 
00548 template <class X>
00549 void Simulator<X>::route(Network<X>* parent, Devs<X>* src, X& x)
00550 {
00551         // Notify event listeners if this is an output event
00552         if (parent != src && (lps == NULL || lps->out_flag != RESTORING_OUTPUT))
00553                 notify_output_listeners(src,x,sched.minPriority());
00554         // No one to do the routing, so return
00555         if (parent == NULL) return;
00556         // Compute the set of receivers for this value
00557         Bag<Event<X> >* recvs = recv_pool.make_obj();
00558         parent->route(x,src,*recvs);
00559         // Deliver the event to each of its targets
00560         Atomic<X>* amodel = NULL;
00561         typename Bag<Event<X> >::iterator recv_iter = recvs->begin();
00562         for (; recv_iter != recvs->end(); recv_iter++)
00563         {
00564                 // Check for self-influencing error condition
00565                 if (src == (*recv_iter).model)
00566                 {
00567                         exception err("Model tried to influence self",src);
00568                         throw err;
00569                 }
00574                 amodel = (*recv_iter).model->typeIsAtomic();
00575                 if (amodel != NULL)
00576                 {
00577                         // Inject it only if it is assigned to our processor
00578                         if (lps == NULL || amodel->getProc() == lps->lp->getID())
00579                                 inject_event(amodel,(*recv_iter).value);
00580                         // Otherwise tell the lp about it
00581                         else if (lps->out_flag != RESTORING_OUTPUT)
00582                                 lps->lp->notifyInput(amodel,(*recv_iter).value);
00583                 }
00584                 // if this is an external output from the parent model
00585                 else if ((*recv_iter).model == parent)
00586                 {
00587                         route(parent->getParent(),parent,(*recv_iter).value);
00588                 }
00589                 // otherwise it is an input to a coupled model
00590                 else
00591                 {
00592                         route((*recv_iter).model->typeIsNetwork(),
00593                         (*recv_iter).model,(*recv_iter).value);
00594                 }
00595         }
00596         recvs->clear();
00597         recv_pool.destroy_obj(recvs);
00598 }
00599 
00600 template <class X>
00601 void Simulator<X>::exec_event(Atomic<X>* model, bool internal, double t)
00602 {
00603         if (!manage_lookahead_data(model)) return;
00604         // Compute the state change
00605         if (model->x == NULL)
00606         {
00607                 model->delta_int();
00608         }
00609         else if (internal)
00610         {
00611                 model->delta_conf(*(model->x));
00612         }
00613         else
00614         {
00615                 model->delta_ext(t-model->tL,*(model->x));
00616         }
00617         // Notify any listeners
00618         notify_state_listeners(model,t);
00619         // Check for a model transition
00620         if (model->model_transition() && model->getParent() != NULL)
00621         {
00622                 model_func_eval_set.insert(model->getParent());
00623         }
00624 }
00625 
00626 template <class X>
00627 void Simulator<X>::getAllChildren(Network<X>* model, Set<Devs<X>*>& s)
00628 {
00629         Set<Devs<X>*> tmp;
00630         // Get the component set
00631         model->getComponents(tmp);
00632         // Find the components of type network and update s recursively
00633         typename Set<Devs<X>*>::iterator iter;
00634         for (iter = tmp.begin(); iter != tmp.end(); iter++)
00635         {
00636                 if ((*iter)->typeIsNetwork() != NULL)
00637                 {
00638                         getAllChildren((*iter)->typeIsNetwork(),s);
00639                 }
00640         }
00641         // Add all of the local level elements to s
00642         for (iter = tmp.begin(); iter != tmp.end(); iter++)
00643         {
00644                 s.insert(*iter);
00645         }
00646 }
00647 
00648 template <class X>
00649 Simulator<X>::~Simulator()
00650 {
00651         // Clean up the models with stale IO
00652         typename Bag<Atomic<X>*>::iterator imm_iter;
00653         for (imm_iter = imm.begin(); imm_iter != imm.end(); imm_iter++)
00654         {
00655                 clean_up(*imm_iter);
00656         }
00657         for (imm_iter = activated.begin(); imm_iter != activated.end(); imm_iter++)
00658         {
00659                 clean_up(*imm_iter);
00660         }
00661 }
00662 
00663 template <class X>
00664 Simulator<X>::Simulator(LogicalProcess<X>* lp):
00665         AbstractSimulator<X>()
00666 {
00667         lps = new lp_support;
00668         lps->lp = lp;
00669         lps->look_ahead = false;
00670         lps->stop_forced = false;
00671         lps->out_flag = OUTPUT_OK;
00672 }
00673 
00674 template <class X>
00675 void Simulator<X>::beginLookahead()
00676 {
00677         if (lps == NULL)
00678         {
00679                 adevs::exception err("tried to lookahead without lp support");
00680                 throw err;
00681         }
00682         lps->look_ahead = true;
00683         if (!imm.empty())
00684                 lps->out_flag = OUTPUT_NOT_OK; 
00685 }
00686 
00687 template <class X>
00688 void Simulator<X>::lookNextEvent()
00689 {
00690         execNextEvent();
00691 }
00692 
00693 template <class X>
00694 void Simulator<X>::endLookahead()
00695 {
00696         if (lps == NULL) return;
00697         typename Bag<Atomic<X>*>::iterator iter = lps->to_restore.begin();
00698         for (; iter != lps->to_restore.end(); iter++)
00699         {
00700                 (*iter)->endLookahead();
00701                 schedule(*iter,(*iter)->tL_cp);
00702                 (*iter)->tL_cp = -1.0;
00703                 assert((*iter)->x == NULL);
00704                 assert((*iter)->y == NULL);
00705         }
00706         lps->to_restore.clear();
00707         assert(imm.empty());
00708         if (lps->out_flag == OUTPUT_NOT_OK)
00709         {
00710                 lps->out_flag = RESTORING_OUTPUT;
00711                 computeNextOutput();
00712                 lps->out_flag = OUTPUT_OK;
00713         }
00714         lps->look_ahead = false;
00715         lps->stop_forced = false;
00716 }
00717 
00718 template <class X>
00719 bool Simulator<X>::manage_lookahead_data(Atomic<X>* model)
00720 {
00721         if (lps == NULL) return true;
00722         if (lps->look_ahead && model->tL_cp < 0.0)
00723         {
00724                 lps->to_restore.insert(model);
00725                 model->tL_cp = model->tL;
00726                 try
00727                 {
00728                         model->beginLookahead();
00729                 }
00730                 catch(method_not_supported_exception err)
00731                 {
00732                         lps->stop_forced = true;
00733                 }
00734         }
00735         return !(lps->stop_forced);
00736 }
00737 
00738 } // End of namespace
00739 
00740 #endif