/home/nutarojj/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>(),lp(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):
00113                         AbstractSimulator<X>(),lp(lp)
00114                 {
00115                 }
00116         private:
00117                 // The processor that this simulator works for, or NULL if no simulator
00118                 LogicalProcess<X>* lp;
00119                 // Bogus input bag for execNextEvent() method
00120                 Bag<Event<X> > bogus_input;
00121                 // The event schedule
00122                 Schedule<X> sched;
00123                 // List of imminent models
00124                 Bag<Atomic<X>*> imm;
00125                 // List of models activated by input
00126                 Bag<Atomic<X>*> activated;
00127                 // Pools of preallocated, commonly used objects
00128                 object_pool<Bag<X> > io_pool;
00129                 object_pool<Bag<Event<X> > > recv_pool;
00130                 // Sets for computing structure changes.
00131                 Set<Devs<X>*> added;
00132                 Set<Devs<X>*> removed;
00133                 Set<Devs<X>*> next;
00134                 Set<Devs<X>*> prev;
00135                 // Model transition functions are evaluated from the bottom up!
00136                 struct bottom_to_top_depth_compare
00137                 {
00138                         bool operator()(const Network<X>* m1, const Network<X>* m2) const
00139                         {
00140                                 unsigned long int d1 = 0, d2 = 0;
00141                                 // Compute depth of m1
00142                                 const Network<X>* m = m1->getParent();
00143                                 while (m != NULL) 
00144                                 {
00145                                         d1++;
00146                                         m = m->getParent();
00147                                 }
00148                                 // Compute depth of m2
00149                                 m = m2->getParent();
00150                                 while (m != NULL)
00151                                 {
00152                                         d2++;
00153                                         m = m->getParent();
00154                                 }
00155                                 // Models at the same depth are sorted by name
00156                                 if (d1 == d2) return m1 < m2;
00157                                 // Otherwise, sort by depth
00158                                 return d1 > d2;
00159                         }
00160                 };
00161                 struct top_to_bottom_depth_compare
00162                 {
00163                         bool operator()(const Devs<X>* m1, const Devs<X>* m2) const
00164                         {
00165                                 unsigned long int d1 = 0, d2 = 0;
00166                                 // Compute depth of m1
00167                                 const Network<X>* m = m1->getParent();
00168                                 while (m != NULL) 
00169                                 {
00170                                         d1++;
00171                                         m = m->getParent();
00172                                 }
00173                                 // Compute depth of m2
00174                                 m = m2->getParent();
00175                                 while (m != NULL)
00176                                 {
00177                                         d2++;
00178                                         m = m->getParent();
00179                                 }
00180                                 // Models at the same depth are sorted by name
00181                                 if (d1 == d2) return m1 < m2;
00182                                 // Otherwise, sort by depth
00183                                 return d1 < d2;
00184                         }
00185                 };
00186                 std::set<Network<X>*,bottom_to_top_depth_compare> model_func_eval_set;
00187                 std::set<Devs<X>*,top_to_bottom_depth_compare> sorted_removed;
00192                 void schedule(Devs<X>* model, double t);
00194                 void route(Network<X>* parent, Devs<X>* src, X& x);
00199                 void inject_event(Atomic<X>* model, X& value);
00204                 void unschedule_model(Devs<X>* model);
00210                 void clean_up(Devs<X>* model);
00216                 void exec_event(Atomic<X>* model, bool internal, double t);
00220                 void getAllChildren(Network<X>* model, Set<Devs<X>*>& s);
00221 };
00222 
00223 template <class X>
00224 void Simulator<X>::computeNextOutput()
00225 {
00226         // If the imminent set is up to date, then just return
00227         if (imm.empty() == false) return;
00228         // Get the imminent models from the schedule. This sets the active flags.
00229         sched.getImminent(imm);
00230         // Compute output functions and route the events. The bags of output
00231         // are held for garbage collection at a later time.
00232         for (typename Bag<Atomic<X>*>::iterator imm_iter = imm.begin(); 
00233                 imm_iter != imm.end(); imm_iter++)
00234         {
00235                 Atomic<X>* model = *imm_iter;
00236                 // If the output for this model has already been computed, then skip it
00237                 if (model->y == NULL)
00238                 {
00239                         model->y = io_pool.make_obj();
00240                         model->output_func(*(model->y));
00241                         // Route each event in y
00242                         for (typename Bag<X>::iterator y_iter = model->y->begin(); 
00243                         y_iter != model->y->end(); y_iter++)
00244                         {
00245                                 route(model->getParent(),model,*y_iter);
00246                         }
00247                 }
00248         }
00249 }
00250 
00251 template <class X>
00252 void Simulator<X>::computeNextState(Bag<Event<X> >& input, double t)
00253 {
00254         // Clean up if there was a previous IO calculation
00255         if (t < sched.minPriority())
00256         {
00257                 typename Bag<Atomic<X>*>::iterator iter;
00258                 for (iter = activated.begin(); iter != activated.end(); iter++)
00259                 {
00260                         clean_up(*iter);
00261                 }
00262                 activated.clear();
00263                 for (iter = imm.begin(); iter != imm.end(); iter++)
00264                 {
00265                         clean_up(*iter);
00266                 }
00267                 imm.clear();
00268         }
00269         // Otherwise, if the internal IO needs to be computed, do it
00270         else if (t == sched.minPriority() && imm.empty())
00271         {
00272                 computeNextOutput();
00273         }
00274         // Apply the injected inputs
00275         for (typename Bag<Event<X> >::iterator iter = input.begin(); 
00276         iter != input.end(); iter++)
00277         {
00278                 Atomic<X>* amodel = (*iter).model->typeIsAtomic();
00279                 if (amodel != NULL)
00280                 {
00281                         inject_event(amodel,(*iter).value);
00282                 }
00283                 else
00284                 {
00285                         route((*iter).model->typeIsNetwork(),(*iter).model,(*iter).value);
00286                 }
00287         }
00288         /*
00289         Compute the states of atomic models.  Store Network models that need to have
00290         their model transition function evaluated in a
00291         special container that will be used when the structure changes are
00292         computed (see exec_event(.)).
00293         */
00294         for (typename Bag<Atomic<X>*>::iterator iter = imm.begin(); 
00295         iter != imm.end(); iter++)
00296         {
00297                 exec_event(*iter,true,t); // Internal and confluent transitions
00298         }
00299         for (typename Bag<Atomic<X>*>::iterator iter = activated.begin(); 
00300         iter != activated.end(); iter++)
00301         {
00302                 exec_event(*iter,false,t); // External transitions
00303         }
00310         if (model_func_eval_set.empty() == false)
00311         {
00312                 while (!model_func_eval_set.empty())
00313                 {
00314                         Network<X>* network_model = *(model_func_eval_set.begin());
00315                         getAllChildren(network_model,prev);
00316                         if (network_model->model_transition() && network_model->getParent() != NULL)
00317                         {
00318                                 model_func_eval_set.insert(network_model->getParent());
00319                         }
00320                         getAllChildren(network_model,next);
00321                         model_func_eval_set.erase(network_model);
00322                 }
00323                 // Find the set of models that were added.
00324                 set_assign_union(added,set_difference(next,prev));
00325                 // Find the set of models that were removed
00326                 set_assign_union(removed,set_difference(prev,next));
00327                 next.clear();
00328                 prev.clear();
00329                 // Any models that moved from one network to another should be left alone.
00330                 Set<Devs<X>*> moved(set_intersect(removed,added));
00331                 for (typename Set<Devs<X>*>::iterator iter = moved.begin();
00332                 iter != moved.end(); iter++)
00333                 {
00334                         typename Set<Devs<X>*>::iterator iter_tmp = added.find(*iter);
00335                         if (iter_tmp != added.end()) added.erase(iter_tmp);
00336                         iter_tmp = removed.find(*iter);
00337                         if (iter_tmp != removed.end()) removed.erase(iter_tmp);
00338                 }
00345                 for (typename Set<Devs<X>*>::iterator iter = added.begin(); 
00346                         iter != added.end(); iter++)
00347                 {
00348                         schedule(*iter,t);
00349                 }
00350                 // Done with the additions
00351                 added.clear();
00352                 // Remove the models that are in the removed set.
00353                 for (typename Set<Devs<X>*>::iterator iter = removed.begin(); 
00354                         iter != removed.end(); iter++)
00355                 {
00356                         clean_up(*iter);
00357                         unschedule_model(*iter);
00358                         sorted_removed.insert(*iter); // Add to a sorted remove set for deletion
00359                 }
00360                 // Done with the unsorted remove set
00361                 removed.clear();
00362                 // Delete the sorted removed models
00363                 while (!sorted_removed.empty())
00364                 {
00365                         // Get the model to erase
00366                         Devs<X>* model_to_remove = *(sorted_removed.begin());
00371                         if (model_to_remove->typeIsNetwork() != NULL)
00372                         {
00373                                 getAllChildren(model_to_remove->typeIsNetwork(),removed);
00374                                 for (typename Set<Devs<X>*>::iterator iter = removed.begin(); 
00375                                         iter != removed.end(); iter++)
00376                                 {
00377                                         sorted_removed.erase(*iter);
00378                                 }
00379                                 removed.clear();
00380                         }
00381                         // Remove the model
00382                         sorted_removed.erase(sorted_removed.begin());
00383                         // Delete the model and its children
00384                         delete model_to_remove;
00385                 }
00386                 // Removed sets should be empty now
00387                 assert(removed.empty());
00388                 assert(sorted_removed.empty());
00389         } // End of the structure change
00390         // Cleanup and reschedule models that changed state in this iteration
00391         // and survived the structure change phase.
00392         for (typename Bag<Atomic<X>*>::iterator iter = imm.begin(); // Schedule the imminents
00393         iter != imm.end(); iter++)
00394         {
00395                 clean_up(*iter);
00396                 schedule(*iter,t);
00397         }
00398         for (typename Bag<Atomic<X>*>::iterator iter = activated.begin(); // Schedule the activated
00399         iter != activated.end(); iter++)
00400         {
00401                 clean_up(*iter);
00402                 schedule(*iter,t);
00403         }
00404         // Empty the bags
00405         imm.clear();
00406         activated.clear();
00407 }
00408 
00409 template <class X>
00410 void Simulator<X>::clean_up(Devs<X>* model)
00411 {
00412         Atomic<X>* amodel = model->typeIsAtomic();
00413         if (amodel != NULL)
00414         {
00415                 amodel->active = false;
00416                 if (amodel->x != NULL)
00417                 {
00418                         amodel->x->clear();
00419                         io_pool.destroy_obj(amodel->x);
00420                         amodel->x = NULL;
00421                 }
00422                 if (amodel->y != NULL)
00423                 {
00424                         amodel->gc_output(*(amodel->y));
00425                         amodel->y->clear();
00426                         io_pool.destroy_obj(amodel->y);
00427                         amodel->y = NULL;
00428                 }
00429         }
00430         else
00431         {
00432                 Set<Devs<X>*> components;
00433                 model->typeIsNetwork()->getComponents(components);
00434                 for (typename Set<Devs<X>*>::iterator iter = components.begin();
00435                 iter != components.end(); iter++)
00436                 {
00437                         clean_up(*iter);
00438                 }
00439         }
00440 }
00441 
00442 template <class X>
00443 void Simulator<X>::unschedule_model(Devs<X>* model)
00444 {
00445         if (model->typeIsAtomic() != NULL)
00446         {
00447                 sched.schedule(model->typeIsAtomic(),DBL_MAX);
00448                 imm.erase(model->typeIsAtomic());
00449                 activated.erase(model->typeIsAtomic());
00450         }
00451         else
00452         {
00453                 Set<Devs<X>*> components;
00454                 model->typeIsNetwork()->getComponents(components);
00455                 for (typename Set<Devs<X>*>::iterator iter = components.begin();
00456                 iter != components.end(); iter++)
00457                 {
00458                         unschedule_model(*iter);
00459                 }
00460         }
00461 }
00462 
00463 template <class X>
00464 void Simulator<X>::schedule(Devs<X>* model, double t)
00465 {
00466         Atomic<X>* a = model->typeIsAtomic();
00467         if (a != NULL)
00468         {
00469                 a->tL = t;
00470                 double dt = a->ta();
00471                 if (dt < 0.0)
00472                 {
00473                         exception err("Negative time advance",a);
00474                         throw err;
00475                 }
00476                 if (dt == DBL_MAX)
00477                         sched.schedule(a,DBL_MAX);
00478                 else
00479                         sched.schedule(a,t+dt);
00480         }
00481         else
00482         {
00483                 Set<Devs<X>*> components;
00484                 model->typeIsNetwork()->getComponents(components);
00485                 typename Set<Devs<X>*>::iterator iter = components.begin();
00486                 for (; iter != components.end(); iter++)
00487                 {
00488                         schedule(*iter,t);
00489                 }
00490         }
00491 }
00492 
00493 template <class X>
00494 void Simulator<X>::inject_event(Atomic<X>* model, X& value)
00495 {
00496         if (model->active == false)
00497         {
00498                 model->active = true;
00499                 activated.insert(model);
00500         }
00501         if (model->x == NULL)
00502         {
00503                 model->x = io_pool.make_obj();
00504         }
00505         model->x->insert(value);
00506 }
00507 
00508 template <class X>
00509 void Simulator<X>::route(Network<X>* parent, Devs<X>* src, X& x)
00510 {
00511         // Notify event listeners if this is an output event
00512         if (parent != src)
00513                 notify_output_listeners(src,x,sched.minPriority());
00514         // No one to do the routing, so return
00515         if (parent == NULL) return;
00516         // Compute the set of receivers for this value
00517         Bag<Event<X> >* recvs = recv_pool.make_obj();
00518         parent->route(x,src,*recvs);
00519         // Deliver the event to each of its targets
00520         Atomic<X>* amodel = NULL;
00521         typename Bag<Event<X> >::iterator recv_iter = recvs->begin();
00522         for (; recv_iter != recvs->end(); recv_iter++)
00523         {
00524                 // Check for self-influencing error condition
00525                 if (src == (*recv_iter).model)
00526                 {
00527                         exception err("Model tried to influence self",src);
00528                         throw err;
00529                 }
00534                 amodel = (*recv_iter).model->typeIsAtomic();
00535                 if (amodel != NULL)
00536                 {
00537                         // Inject it only if it is assigned to our processor
00538                         if (lp == NULL || amodel->getProc() == lp->getID())
00539                                 inject_event(amodel,(*recv_iter).value);
00540                         // Otherwise tell the lp about it
00541                         else lp->notifyInput(amodel,(*recv_iter).value);
00542                 }
00543                 // if this is an external output from the parent model
00544                 else if ((*recv_iter).model == parent)
00545                 {
00546                         route(parent->getParent(),parent,(*recv_iter).value);
00547                 }
00548                 // otherwise it is an input to a coupled model
00549                 else
00550                 {
00551                         route((*recv_iter).model->typeIsNetwork(),
00552                         (*recv_iter).model,(*recv_iter).value);
00553                 }
00554         }
00555         recvs->clear();
00556         recv_pool.destroy_obj(recvs);
00557 }
00558 
00559 template <class X>
00560 void Simulator<X>::exec_event(Atomic<X>* model, bool internal, double t)
00561 {
00562         // Compute the state change
00563         if (model->x == NULL)
00564         {
00565                 model->delta_int();
00566         }
00567         else if (internal)
00568         {
00569                 model->delta_conf(*(model->x));
00570         }
00571         else
00572         {
00573                 model->delta_ext(t-model->tL,*(model->x));
00574         }
00575         // Notify any listeners
00576         notify_state_listeners(model,t);
00577         // Check for a model transition
00578         if (model->model_transition() && model->getParent() != NULL)
00579         {
00580                 model_func_eval_set.insert(model->getParent());
00581         }
00582 }
00583 
00584 template <class X>
00585 void Simulator<X>::getAllChildren(Network<X>* model, Set<Devs<X>*>& s)
00586 {
00587         Set<Devs<X>*> tmp;
00588         // Get the component set
00589         model->getComponents(tmp);
00590         // Find the components of type network and update s recursively
00591         typename Set<Devs<X>*>::iterator iter;
00592         for (iter = tmp.begin(); iter != tmp.end(); iter++)
00593         {
00594                 if ((*iter)->typeIsNetwork() != NULL)
00595                 {
00596                         getAllChildren((*iter)->typeIsNetwork(),s);
00597                 }
00598         }
00599         // Add all of the local level elements to s
00600         for (iter = tmp.begin(); iter != tmp.end(); iter++)
00601         {
00602                 s.insert(*iter);
00603         }
00604 }
00605 
00606 template <class X>
00607 Simulator<X>::~Simulator()
00608 {
00609         // Clean up the models with stale IO
00610         typename Bag<Atomic<X>*>::iterator imm_iter;
00611         for (imm_iter = imm.begin(); imm_iter != imm.end(); imm_iter++)
00612         {
00613                 clean_up(*imm_iter);
00614         }
00615         for (imm_iter = activated.begin(); imm_iter != activated.end(); imm_iter++)
00616         {
00617                 clean_up(*imm_iter);
00618         }
00619 }
00620 
00621 } // End of namespace
00622 
00623 #endif

Generated on Mon Sep 20 14:35:39 2010 for adevs by  doxygen 1.4.7