adevs
adevs_base.h
1 #ifndef _adevs_model_h_
2 #define _adevs_model_h_
3 #include <vector>
4 #include <exception>
5 #include <cassert>
6 #include <stdexcept>
7 #include <cstdlib>
8 #include <iostream>
9 #include <string>
10 #include <sstream>
11 #include "adevs_time.h"
12 
14 #define ADEVS_ERROR_CHECK(cond,model,msg) \
15  if (!(cond)) { \
16  std::ostringstream buf; \
17  buf << __FILE__ << ":" << __LINE__ << ":" << model->name() << ":" << msg; \
18  throw std::logic_error(buf.str()); \
19  }
20 
21 namespace adevs
22 {
23 
24 template <typename DataType, typename TimeType> class Model;
25 template <typename DataType, typename TimeType> class Simulator;
26 
37 template <typename DataType, typename TimeType=Time>
38 class SimEnv
39 {
40  public:
49  virtual void send(
52  DataType data) = 0;
60  virtual void add(Model<DataType,TimeType> *model) = 0;
67  virtual void remove(Model<DataType,TimeType> *model) = 0;
69  virtual TimeType now() = 0;
71  virtual ~SimEnv(){}
72 };
73 
79 template <typename DataType, typename TimeType=Time>
80 class Model
81 {
82  public:
83  Model():priority(adevs_inf<TimeType>()),heap_pos(0),
84  remove(false),msgs(NULL),defer(NULL){}
94  virtual TimeType init(SimEnv<DataType,TimeType>* env) = 0;
101  virtual void fini(TimeType now) = 0;
113  virtual TimeType update(
114  SimEnv<DataType,TimeType> *env, std::vector<DataType> &x) = 0;
123  virtual TimeType update(SimEnv<DataType,TimeType> *env) = 0;
140  virtual std::pair<Model<DataType,TimeType>*,DataType>
141  relay(Model<DataType,TimeType> *src, DataType x) {
142  return std::pair<Model<DataType,TimeType>*,DataType>(this,x);
143  }
151  virtual std::string name() { return ""; }
153  virtual ~Model()
154  {
155  if (msgs != NULL)
156  delete msgs;
157  if (defer != NULL)
158  delete defer;
159  }
169  void reset()
170  {
171  if (msgs != NULL) delete msgs;
172  if (defer != NULL ) delete defer;
173  msgs = defer = NULL;
174  remove = false;
175  heap_pos = 0;
176  priority = adevs_inf<TimeType>();
177  }
178  private:
179  friend class Simulator<DataType,TimeType>;
180  TimeType priority;
181  unsigned heap_pos;
182  bool remove;
183  std::vector<DataType> *msgs, *defer;
184 };
185 
186 
192 template <typename DataType, typename TimeType=Time>
193 class Simulator: public SimEnv<DataType,TimeType>
194 {
195  public:
200  Simulator(TimeType tStart = adevs_zero<TimeType>());
202  ~Simulator();
211  void send(
214  DataType data);
221  void add(Model<DataType,TimeType> *model);
228  void remove(Model<DataType,TimeType> *model);
230  TimeType now() { return m_now; }
232  TimeType next_event_time() const;
234  void exec_next_event();
236  void exec_until(TimeType t);
237  private:
238  std::vector<std::vector<DataType>* > msg_lists;
239  std::vector<Model<DataType,TimeType>* > heap;
240  TimeType m_now;
241  void percolate_down(Model<DataType,TimeType>* model);
242  void percolate_up(Model<DataType,TimeType>* model);
243  void percolate_away(Model<DataType,TimeType>* model);
244  void percolate_in(Model<DataType,TimeType>* model);
245  std::vector<DataType>* get_message_list();
246  void replace_message_list(std::vector<DataType>* msgs);
247 };
248 
249 template <typename DataType, typename TimeType>
251  m_now(tStart)
252 {
253  // Put a sentinel at the top of the heap
254  heap.push_back(NULL);
255 }
256 
257 template <typename DataType, typename TimeType>
259 {
260  if (heap.size() == 1) return adevs_inf<TimeType>();
261  return heap[1]->priority;
262 }
263 
264 template <typename DataType, typename TimeType>
266 {
267  while (next_event_time() <= t && next_event_time() < adevs_inf<TimeType>())
268  exec_next_event();
269  m_now = t;
270 }
271 
272 template <typename DataType, typename TimeType>
274 {
275  // If the heap is empty then there is nothing to do
276  if (heap.size() == 1)
277  return;
278  // The current time will be the time of the next event
279  m_now = heap[1]->priority;
280  // Update everyone that is imminent
281  while ((heap.size() > 1) && (heap[1]->priority == m_now))
282  {
283  // Get the model at the top
284  Model<DataType,TimeType>* model = heap[1];
285  // If this is a model to remove, then chuck it
286  if (model->remove)
287  {
288  percolate_away(model);
289  replace_message_list(model->msgs);
290  replace_message_list(model->defer);
291  model->msgs = model->defer = NULL;
292  model->remove = false;
293  // Do this last because the model might delete itself
294  model->fini(m_now);
295  }
296  // Update its state and get the time advance
297  else
298  {
299  if (model->msgs != NULL)
300  {
301  model->priority = model->update(this,*(model->msgs));
302  // Time must advance!
303  ADEVS_ERROR_CHECK(m_now < model->priority,model,"update(x) <= now()")
304  }
305  else
306  {
307  model->priority = model->update(this);
308  // Time must advance!
309  ADEVS_ERROR_CHECK(m_now < model->priority,model,"update() <= now()")
310  }
311  // Clear the message list
312  replace_message_list(model->msgs);
313  // If we have messages for now + adevs_epsilon() get those ready
314  model->msgs = model->defer;
315  // Now those messages are not defered
316  model->defer = NULL;
317  // Models to be removed or to receive input go at the next
318  // logical instant of time
319  if (model->msgs != NULL || model->remove)
320  model->priority = m_now + adevs_epsilon<TimeType>();
321  assert(m_now < model->priority);
322  // Put it into the schedule
323  if (model->priority < adevs_inf<TimeType>())
324  percolate_down(model);
325  else
326  percolate_away(model);
327  }
328  }
329 }
330 
331 template <typename DataType, typename TimeType>
333 {
334  // Assign the model a state
335  TimeType priority = model->init(this);
336  ADEVS_ERROR_CHECK(m_now < priority,model,"init() <= now()")
337  ADEVS_ERROR_CHECK(
338  (model->msgs != NULL && model->priority == m_now+adevs_epsilon<TimeType>()) ||
339  model->heap_pos == 0,model,"new model is already active")
340  if (model->msgs == NULL)
341  {
342  model->priority = priority;
343  if (model->priority < adevs_inf<TimeType>())
344  percolate_in(model);
345  }
346 }
347 
348 template <typename DataType, typename TimeType>
350 {
351  model->remove = true;
352  model->priority = m_now + adevs_epsilon<TimeType>();
353  // Put it in the schedule
354  if (model->heap_pos == 0)
355  percolate_in(model);
356  // Or move it up to the next time increment from now
357  else
358  percolate_up(model);
359 }
360 
361 template <typename DataType, typename TimeType>
365  DataType data)
366 {
367  std::pair<Model<DataType,TimeType>*,DataType> r(dst->relay(src,data));
368  /* If we are relaying this data to another model */
369  while (r.first != dst && r.first != NULL)
370  {
371  /* Send it to the other model */
372  send(dst,r.first,r.second);
373  /* See who else we should send it to */
374  r = dst->relay(src,data);
375  }
376  /* If we are done then return */
377  if (r.first == NULL) return;
378  assert(r.first == dst);
379  /* Handle a model that is due to come up */
380  if (dst->priority == m_now)
381  {
382  if (dst->defer == NULL)
383  dst->defer = get_message_list();
384  dst->defer->push_back(r.second);
385  }
386  /* Handle a model that won't act until the future */
387  else
388  {
389  if (dst->msgs == NULL)
390  dst->msgs = get_message_list();
391  dst->msgs->push_back(r.second);
392  dst->priority = m_now + adevs_epsilon<TimeType>();
393  // Put it in the schedule
394  assert(dst->priority < adevs_inf<TimeType>());
395  if (dst->heap_pos == 0)
396  percolate_in(dst);
397  // Or move it up to the next time increment from now
398  else
399  percolate_up(dst);
400  }
401 }
402 
403 template <typename DataType, typename TimeType>
405 {
406  assert(model->priority < adevs_inf<TimeType>());
407  assert(heap[model->heap_pos] == model);
408  unsigned index = model->heap_pos;
409  /* priority < heap_parent->priority stops percolating up
410  * as soon as possible. */
411  while (heap[index/2] != NULL && model->priority < heap[index/2]->priority)
412  {
413  heap[index] = heap[index/2];
414  heap[index]->heap_pos = index;
415  index /= 2;
416  }
417  heap[index] = model;
418  heap[index]->heap_pos = index;
419  assert(index != 0);
420 }
421 
422 template <typename DataType, typename TimeType>
424 {
425  assert(heap[model->heap_pos] == model);
426  unsigned child, index = model->heap_pos;
427  for (; index*2 < heap.size(); index = child)
428  {
429  child = index*2;
430  if (child+1 < heap.size() && heap[child+1]->priority < heap[child]->priority)
431  child++;
432  if (heap[child]->priority < model->priority)
433  {
434  heap[index] = heap[child];
435  heap[index]->heap_pos = index;
436  }
437  else break;
438  }
439  heap[index] = model;
440  heap[index]->heap_pos = index;
441  assert(index != 0 && index < heap.size());
442 }
443 
444 template <typename DataType, typename TimeType>
446 {
447  assert(model->heap_pos == 0);
448  model->heap_pos = heap.size();
449  heap.push_back(model);
450  percolate_up(model);
451 }
452 
453 template <typename DataType, typename TimeType>
455 {
456  // Remove the model by plugging the heap hole and then moving the plug
457  Model<DataType,TimeType>* move = heap[model->heap_pos] = heap.back();
458  move->heap_pos = model->heap_pos;
459  heap.pop_back();
460  if (heap.size() > 1)
461  {
462  const unsigned parent = move->heap_pos/2;
463  if (heap[parent] != NULL &&
464  heap[move->heap_pos]->priority < heap[parent]->priority)
465  percolate_up(move);
466  else
467  percolate_down(move);
468  }
469  model->priority = adevs_inf<TimeType>();
470  model->heap_pos = 0;
471 }
472 
473 template <typename DataType, typename TimeType>
474 std::vector<DataType>* Simulator<DataType,TimeType>::get_message_list()
475 {
476  std::vector<DataType>* result;
477  if (msg_lists.empty())
478  return (result = new std::vector<DataType>());
479  result = msg_lists.back();
480  msg_lists.pop_back();
481  return result;
482 }
483 
484 template <typename DataType, typename TimeType>
486  std::vector<DataType>* msgs)
487 {
488  if (msgs == NULL) return;
489  msgs->clear();
490  msg_lists.push_back(msgs);
491 }
492 
493 template <typename DataType, typename TimeType>
495 {
496  for (unsigned i = 0; i < msg_lists.size(); i++)
497  delete msg_lists[i];
498 }
499 
500 }; // end of namespace
501 
502 #endif
The simulator generates trajectories for its models.
Definition: adevs_base.h:25
void reset()
Reset simulation support to reuse the model in a new simulation context.
Definition: adevs_base.h:169
virtual void add(Model< DataType, TimeType > *model)=0
Add a model to the simulator.
void remove(Model< DataType, TimeType > *model)
Remove a model from the simulation context.
Definition: adevs_base.h:349
virtual ~SimEnv()
Destructor.
Definition: adevs_base.h:71
virtual std::pair< Model< DataType, TimeType > *, DataType > relay(Model< DataType, TimeType > *src, DataType x)
Relay a message to another model.
Definition: adevs_base.h:141
virtual ~Model()
Destructor.
Definition: adevs_base.h:153
~Simulator()
Destructor leaves all models intact.
Definition: adevs_base.h:494
void add(Model< DataType, TimeType > *model)
Add a model to the simulation context.
Definition: adevs_base.h:332
void exec_next_event()
Execute update() methods at the next event time.
Definition: adevs_base.h:273
virtual TimeType init(SimEnv< DataType, TimeType > *env)=0
Called when the model is added to the simulation.
Definition: adevs_base.h:21
virtual TimeType update(SimEnv< DataType, TimeType > *env, std::vector< DataType > &x)=0
Called to assign a new state to the model at now() when input is present.
Simulator(TimeType tStart=adevs_zero< TimeType >())
Constructor sets the simulation start time.
Definition: adevs_base.h:250
virtual std::string name()
Return a name for this model.
Definition: adevs_base.h:151
virtual void send(Model< DataType, TimeType > *src, Model< DataType, TimeType > *dst, DataType data)=0
Send a message to a model.
Interface to a simulation context for sending messages, getting the time, and adding or removing mode...
Definition: adevs_base.h:38
virtual void fini(TimeType now)=0
Called after the model has been removed from the simulation.
A model in the simulation.
Definition: adevs_base.h:24
void exec_until(TimeType t)
Advance until the simulation time until it equals the supplied time.
Definition: adevs_base.h:265
TimeType next_event_time() const
Returns the time of the next event.
Definition: adevs_base.h:258
void send(Model< DataType, TimeType > *src, Model< DataType, TimeType > *dst, DataType data)
Send a message to a model.
Definition: adevs_base.h:362
TimeType now()
Returns the current simulation time.
Definition: adevs_base.h:230
virtual TimeType now()=0
Get the current time.