adevs
adevs_simulator.h
1 
31 #ifndef __adevs_simulator_h_
32 #define __adevs_simulator_h_
33 #include "adevs_abstract_simulator.h"
34 #include "adevs_models.h"
35 #include "adevs_event_listener.h"
36 #include "adevs_sched.h"
37 #include "adevs_bag.h"
38 #include "adevs_set.h"
39 #include "object_pool.h"
40 #include "adevs_lp.h"
41 #include <cassert>
42 #include <cstdlib>
43 #include <iostream>
44 #include <vector>
45 
46 namespace adevs
47 {
48 
55 template <class X, class T = double> class Simulator:
56  public AbstractSimulator<X,T>,
57  private Schedule<X,T>::ImminentVisitor
58 {
59  public:
67  AbstractSimulator<X,T>(),
68  Schedule<X,T>::ImminentVisitor(),
69  lps(NULL)
70  {
71  schedule(model,adevs_zero<T>());
72  }
78  {
79  return sched.minPriority();
80  }
83  {
85  computeNextState(bogus_input,sched.minPriority());
86  }
88  void execUntil(T tend)
89  {
90  while (nextEventTime() <= tend
91  && nextEventTime() < adevs_inf<T>()) {
92  execNextEvent();
93  }
94  }
100  void computeNextOutput();
109  void computeNextState(Bag<Event<X,T> >& input, T t);
115  ~Simulator();
120  void addModel(Atomic<X,T>* model)
121  {
122  schedule(model,adevs_zero<T>());
123  }
128  Simulator(LogicalProcess<X,T>* lp);
140  void beginLookahead();
145  void endLookahead();
152  void lookNextEvent();
153  private:
154  typedef enum { OUTPUT_OK, OUTPUT_NOT_OK, RESTORING_OUTPUT } OutputStatus;
155  // Structure to support parallel computing by a logical process
156  struct lp_support
157  {
158  // The processor that this simulator works for
159  LogicalProcess<X,T>* lp;
160  bool look_ahead, stop_forced;
161  OutputStatus out_flag;
162  Bag<Atomic<X,T>*> to_restore;
163  };
164  // This is NULL if the simulator is not supporting a logical process
165  lp_support* lps;
166  // Bogus input bag for execNextEvent() method
167  Bag<Event<X,T> > bogus_input;
168  // The event schedule
169  Schedule<X,T> sched;
170  // List of models that are imminent or activated by input
171  Bag<Atomic<X,T>*> activated;
172  // Pools of preallocated, commonly used objects
173  object_pool<Bag<X> > io_pool;
174  object_pool<Bag<Event<X,T> > > recv_pool;
175  // Sets for computing structure changes.
176  Bag<Devs<X,T>*> added;
177  Bag<Devs<X,T>*> removed;
178  Set<Devs<X,T>*> next;
179  Set<Devs<X,T>*> prev;
180  // Model transition functions are evaluated from the bottom up!
181  struct bottom_to_top_depth_compare
182  {
183  bool operator()(const Network<X,T>* m1, const Network<X,T>* m2) const
184  {
185  unsigned long int d1 = 0, d2 = 0;
186  // Compute depth of m1
187  const Network<X,T>* m = m1->getParent();
188  while (m != NULL)
189  {
190  d1++;
191  m = m->getParent();
192  }
193  // Compute depth of m2
194  m = m2->getParent();
195  while (m != NULL)
196  {
197  d2++;
198  m = m->getParent();
199  }
200  // Models at the same depth are sorted by name
201  if (d1 == d2) return m1 < m2;
202  // Otherwise, sort by depth
203  return d1 > d2;
204  }
205  };
206  struct top_to_bottom_depth_compare
207  {
208  bool operator()(const Devs<X,T>* m1, const Devs<X,T>* m2) const
209  {
210  unsigned long int d1 = 0, d2 = 0;
211  // Compute depth of m1
212  const Network<X,T>* m = m1->getParent();
213  while (m != NULL)
214  {
215  d1++;
216  m = m->getParent();
217  }
218  // Compute depth of m2
219  m = m2->getParent();
220  while (m != NULL)
221  {
222  d2++;
223  m = m->getParent();
224  }
225  // Models at the same depth are sorted by name
226  if (d1 == d2) return m1 < m2;
227  // Otherwise, sort by depth
228  return d1 < d2;
229  }
230  };
231  std::set<Network<X,T>*,bottom_to_top_depth_compare> model_func_eval_set;
232  std::set<Devs<X,T>*,top_to_bottom_depth_compare> sorted_removed;
237  void schedule(Devs<X,T>* model, T t);
239  void route(Network<X,T>* parent, Devs<X,T>* src, X& x);
245  void inject_event(Atomic<X,T>* model, X& value);
250  void unschedule_model(Devs<X,T>* model);
256  void clean_up(Devs<X,T>* model);
263  void exec_event(Atomic<X,T>* model, T t);
267  void getAllChildren(Network<X,T>* model, Set<Devs<X,T>*>& s);
273  bool manage_lookahead_data(Atomic<X,T>* model);
277  void visit(Atomic<X,T>* model);
278 };
279 
280 template <class X, class T>
281 void Simulator<X,T>::visit(Atomic<X,T>* model)
282 {
283  assert(model->y == NULL);
284  model->y = io_pool.make_obj();
285  // Put it in the active list if it is not already there
286  if (model->x == NULL)
287  activated.insert(model);
288  // Compute output functions and route the events. The bags of output
289  // are held for garbage collection at a later time.
290  model->output_func(*(model->y));
291  // Route each event in y
292  for (typename Bag<X>::iterator y_iter = model->y->begin();
293  y_iter != model->y->end(); y_iter++)
294  {
295  route(model->getParent(),model,*y_iter);
296  }
297 }
298 
299 template <class X, class T>
301 {
302  // If the imminent set is up to date, then just return
303  if (activated.empty() == false) return;
304  // Get the imminent models from the schedule.
305  sched.visitImminent(this);
306 }
307 
308 template <class X, class T>
310 {
311  // Clean up if there was a previous IO calculation
312  if (t < sched.minPriority())
313  {
314  typename Bag<Atomic<X,T>*>::iterator iter;
315  for (iter = activated.begin(); iter != activated.end(); iter++)
316  {
317  clean_up(*iter);
318  }
319  activated.clear();
320  }
321  // Otherwise, if the internal IO needs to be computed, do it
322  else if (t == sched.minPriority())
323  {
324  computeNextOutput();
325  }
326  // Apply the injected inputs
327  for (typename Bag<Event<X,T> >::iterator iter = input.begin();
328  iter != input.end(); iter++)
329  {
330  Atomic<X,T>* amodel = (*iter).model->typeIsAtomic();
331  if (amodel != NULL)
332  {
333  inject_event(amodel,(*iter).value);
334  }
335  else
336  {
337  route((*iter).model->typeIsNetwork(),(*iter).model,(*iter).value);
338  }
339  }
340  /*
341  * Compute the states of atomic models. Store Network models that
342  * need to have their model transition function evaluated in a
343  * special container that will be used when the structure changes are
344  * computed (see exec_event(.)).
345  */
346  for (typename Bag<Atomic<X,T>*>::iterator iter = activated.begin();
347  iter != activated.end(); iter++)
348  {
349  exec_event(*iter,t);
350  }
357  if (model_func_eval_set.empty() == false)
358  {
359  while (!model_func_eval_set.empty())
360  {
361  Network<X,T>* network_model = *(model_func_eval_set.begin());
362  getAllChildren(network_model,prev);
363  if (network_model->model_transition() &&
364  network_model->getParent() != NULL)
365  {
366  model_func_eval_set.insert(network_model->getParent());
367  }
368  getAllChildren(network_model,next);
369  model_func_eval_set.erase(network_model);
370  }
371  // Find the set of models that were added.
372  set_assign_diff(added,next,prev);
373  // Find the set of models that were removed
374  set_assign_diff(removed,prev,next);
375  // Intersection of added and removed is always empty, so no need to look
376  // for models in both (an earlier version of the code did this).
377  next.clear();
378  prev.clear();
385  for (typename Bag<Devs<X,T>*>::iterator iter = added.begin();
386  iter != added.end(); iter++)
387  {
388  schedule(*iter,t);
389  }
390  // Done with the additions
391  added.clear();
392  // Remove the models that are in the removed set.
393  for (typename Bag<Devs<X,T>*>::iterator iter = removed.begin();
394  iter != removed.end(); iter++)
395  {
396  clean_up(*iter);
397  unschedule_model(*iter);
398  // Add to a sorted remove set for deletion
399  sorted_removed.insert(*iter);
400  }
401  // Done with the unsorted remove set
402  removed.clear();
403  // Delete the sorted removed models
404  while (!sorted_removed.empty())
405  {
406  // Get the model to erase
407  Devs<X,T>* model_to_remove = *(sorted_removed.begin());
412  if (model_to_remove->typeIsNetwork() != NULL)
413  {
414  getAllChildren(model_to_remove->typeIsNetwork(),prev);
415  for (typename Set<Devs<X,T>*>::iterator iter = prev.begin();
416  iter != prev.end(); iter++)
417  {
418  sorted_removed.erase(*iter);
419  }
420  prev.clear();
421  }
422  // Remove the model
423  sorted_removed.erase(sorted_removed.begin());
424  // Delete the model and its children
425  delete model_to_remove;
426  }
427  // Removed sets should be empty now
428  assert(prev.empty());
429  assert(sorted_removed.empty());
430  } // End of the structure change
431  // Cleanup and reschedule models that changed state in this iteration
432  // and survived the structure change phase.
433  for (typename Bag<Atomic<X,T>*>::iterator iter = activated.begin();
434  iter != activated.end(); iter++)
435  {
436  clean_up(*iter);
437  schedule(*iter,t);
438  }
439  // Empty the bags
440  activated.clear();
441  // If we are looking ahead, throw an exception if a stop was forced
442  if (lps != NULL && lps->stop_forced)
443  {
445  throw err;
446  }
447 }
448 
449 template <class X, class T>
451 {
452  Atomic<X,T>* amodel = model->typeIsAtomic();
453  if (amodel != NULL)
454  {
455  if (amodel->x != NULL)
456  {
457  amodel->x->clear();
458  io_pool.destroy_obj(amodel->x);
459  amodel->x = NULL;
460  }
461  if (amodel->y != NULL)
462  {
463  amodel->gc_output(*(amodel->y));
464  amodel->y->clear();
465  io_pool.destroy_obj(amodel->y);
466  amodel->y = NULL;
467  }
468  }
469  else
470  {
471  Set<Devs<X,T>*> components;
472  model->typeIsNetwork()->getComponents(components);
473  for (typename Set<Devs<X,T>*>::iterator iter = components.begin();
474  iter != components.end(); iter++)
475  {
476  clean_up(*iter);
477  }
478  }
479 }
480 
481 template <class X, class T>
482 void Simulator<X,T>::unschedule_model(Devs<X,T>* model)
483 {
484  if (model->typeIsAtomic() != NULL)
485  {
486  sched.schedule(model->typeIsAtomic(),adevs_inf<T>());
487  activated.erase(model->typeIsAtomic());
488  }
489  else
490  {
491  Set<Devs<X,T>*> components;
492  model->typeIsNetwork()->getComponents(components);
493  for (typename Set<Devs<X,T>*>::iterator iter = components.begin();
494  iter != components.end(); iter++)
495  {
496  unschedule_model(*iter);
497  }
498  }
499 }
500 
501 template <class X, class T>
502 void Simulator<X,T>::schedule(Devs<X,T>* model, T t)
503 {
504  Atomic<X,T>* a = model->typeIsAtomic();
505  if (a != NULL)
506  {
507  a->tL = t;
508  T dt = a->ta();
509  if (dt < adevs_zero<T>())
510  {
511  exception err("Negative time advance",a);
512  throw err;
513  }
514  if (dt == adevs_inf<T>())
515  sched.schedule(a,adevs_inf<T>());
516  else
517  sched.schedule(a,t+dt);
518  }
519  else
520  {
521  Set<Devs<X,T>*> components;
522  model->typeIsNetwork()->getComponents(components);
523  typename Set<Devs<X,T>*>::iterator iter = components.begin();
524  for (; iter != components.end(); iter++)
525  {
526  schedule(*iter,t);
527  }
528  }
529 }
530 
531 template <class X, class T>
532 void Simulator<X,T>::inject_event(Atomic<X,T>* model, X& value)
533 {
534  if (model->x == NULL)
535  {
536  if (model->y == NULL)
537  activated.insert(model);
538  model->x = io_pool.make_obj();
539  }
540  model->x->insert(value);
541 }
542 
543 template <class X, class T>
544 void Simulator<X,T>::route(Network<X,T>* parent, Devs<X,T>* src, X& x)
545 {
546  // Notify event listeners if this is an output event
547  if (parent != src && (lps == NULL || lps->out_flag != RESTORING_OUTPUT))
548  this->notify_output_listeners(src,x,sched.minPriority());
549  // No one to do the routing, so return
550  if (parent == NULL) return;
551  // Compute the set of receivers for this value
552  Bag<Event<X,T> >* recvs = recv_pool.make_obj();
553  parent->route(x,src,*recvs);
554  // Deliver the event to each of its targets
555  Atomic<X,T>* amodel = NULL;
556  typename Bag<Event<X,T> >::iterator recv_iter = recvs->begin();
557  for (; recv_iter != recvs->end(); recv_iter++)
558  {
559  // Check for self-influencing error condition
560  if (src == (*recv_iter).model)
561  {
562  exception err("Model tried to influence self",src);
563  throw err;
564  }
569  amodel = (*recv_iter).model->typeIsAtomic();
570  if (amodel != NULL)
571  {
572  // Inject it only if it is assigned to our processor
573  if (lps == NULL || amodel->getProc() == lps->lp->getID())
574  inject_event(amodel,(*recv_iter).value);
575  // Otherwise tell the lp about it
576  else if (lps->out_flag != RESTORING_OUTPUT)
577  lps->lp->notifyInput(amodel,(*recv_iter).value);
578  }
579  // if this is an external output from the parent model
580  else if ((*recv_iter).model == parent)
581  {
582  route(parent->getParent(),parent,(*recv_iter).value);
583  }
584  // otherwise it is an input to a coupled model
585  else
586  {
587  route((*recv_iter).model->typeIsNetwork(),
588  (*recv_iter).model,(*recv_iter).value);
589  }
590  }
591  recvs->clear();
592  recv_pool.destroy_obj(recvs);
593 }
594 
595 template <class X, class T>
596 void Simulator<X,T>::exec_event(Atomic<X,T>* model, T t)
597 {
598  if (!manage_lookahead_data(model)) return;
599  // Internal event
600  if (model->x == NULL)
601  model->delta_int();
602  // Confluent event
603  else if (model->y != NULL)
604  model->delta_conf(*(model->x));
605  // External event
606  else
607  model->delta_ext(t-model->tL,*(model->x));
608  // Notify any listeners
609  this->notify_state_listeners(model,t);
610  // Check for a model transition
611  if (model->model_transition() && model->getParent() != NULL)
612  {
613  model_func_eval_set.insert(model->getParent());
614  }
615 }
616 
617 template <class X, class T>
618 void Simulator<X,T>::getAllChildren(Network<X,T>* model, Set<Devs<X,T>*>& s)
619 {
620  Set<Devs<X,T>*> tmp;
621  // Get the component set
622  model->getComponents(tmp);
623  // Find the components of type network and update s recursively
624  typename Set<Devs<X,T>*>::iterator iter;
625  for (iter = tmp.begin(); iter != tmp.end(); iter++)
626  {
627  if ((*iter)->typeIsNetwork() != NULL)
628  {
629  getAllChildren((*iter)->typeIsNetwork(),s);
630  }
631  }
632  // Add all of the local level elements to s
633  for (iter = tmp.begin(); iter != tmp.end(); iter++)
634  {
635  s.insert(*iter);
636  }
637 }
638 
639 template <class X, class T>
641 {
642  // Clean up the models with stale IO
643  typename Bag<Atomic<X,T>*>::iterator iter;
644  for (iter = activated.begin(); iter != activated.end(); iter++)
645  {
646  clean_up(*iter);
647  }
648 }
649 
650 template <class X, class T>
651 Simulator<X,T>::Simulator(LogicalProcess<X,T>* lp):
652  AbstractSimulator<X,T>()
653 {
654  lps = new lp_support;
655  lps->lp = lp;
656  lps->look_ahead = false;
657  lps->stop_forced = false;
658  lps->out_flag = OUTPUT_OK;
659 }
660 
661 template <class X, class T>
663 {
664  if (lps == NULL)
665  {
666  adevs::exception err("tried to lookahead without lp support");
667  throw err;
668  }
669  lps->look_ahead = true;
670  if (!activated.empty())
671  lps->out_flag = OUTPUT_NOT_OK;
672 }
673 
674 template <class X, class T>
676 {
677  execNextEvent();
678 }
679 
680 template <class X, class T>
682 {
683  if (lps == NULL) return;
684  typename Bag<Atomic<X,T>*>::iterator iter = lps->to_restore.begin();
685  for (; iter != lps->to_restore.end(); iter++)
686  {
687  (*iter)->endLookahead();
688  schedule(*iter,(*iter)->tL_cp);
689  (*iter)->tL_cp = adevs_sentinel<T>();
690  assert((*iter)->x == NULL);
691  assert((*iter)->y == NULL);
692  }
693  lps->to_restore.clear();
694  assert(activated.empty());
695  if (lps->out_flag == OUTPUT_NOT_OK)
696  {
697  lps->out_flag = RESTORING_OUTPUT;
698  computeNextOutput();
699  lps->out_flag = OUTPUT_OK;
700  }
701  lps->look_ahead = false;
702  lps->stop_forced = false;
703 }
704 
705 template <class X, class T>
707 {
708  if (lps == NULL) return true;
709  if (lps->look_ahead && model->tL_cp < adevs_zero<T>())
710  {
711  lps->to_restore.insert(model);
712  model->tL_cp = model->tL;
713  try
714  {
715  model->beginLookahead();
716  }
717  catch(method_not_supported_exception err)
718  {
719  lps->stop_forced = true;
720  }
721  }
722  return !(lps->stop_forced);
723 }
724 
725 } // End of namespace
726 
727 #endif