Soar Kernel  9.3.2 08-06-12
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
soar_module.h
Go to the documentation of this file.
1 /*************************************************************************
2  * PLEASE SEE THE FILE "license.txt" (INCLUDED WITH THIS SOFTWARE PACKAGE)
3  * FOR LICENSE AND COPYRIGHT INFORMATION.
4  *************************************************************************/
5 
6 /*************************************************************************
7  *
8  * file: soar_module.h
9  *
10  * =======================================================================
11  */
12 
13 #ifndef SOAR_MODULE_H
14 #define SOAR_MODULE_H
15 
16 #include <portability.h>
17 
18 #include <map>
19 #include <string>
20 #include <set>
21 #include <list>
22 #include <functional>
23 #include <assert.h>
24 #include <cmath>
25 
26 #include "misc.h"
27 #include "symtab.h"
28 #include "mem.h"
29 
30 typedef struct wme_struct wme;
32 
33 // separates this functionality
34 // just for Soar modules
35 namespace soar_module
36 {
38  // Utility functions
40 
41  typedef std::set< wme* > wme_set;
42 
43  typedef struct symbol_triple_struct
44  {
48 
49  symbol_triple_struct( Symbol* new_id, Symbol* new_attr, Symbol* new_value ): id(new_id), attr(new_attr), value(new_value) {}
50  } symbol_triple;
51  typedef std::list< symbol_triple* > symbol_triple_list;
52 
53  wme *add_module_wme( agent *my_agent, Symbol *id, Symbol *attr, Symbol *value );
54  void remove_module_wme( agent *my_agent, wme *w );
55  instantiation* make_fake_instantiation( agent* my_agent, Symbol* state, wme_set* conditions, symbol_triple_list* actions );
56 
58  // Predicates
60 
61  // a functor for validating parameter values
62  template <typename T>
63  class predicate: public std::unary_function<T, bool>
64  {
65  public:
66  virtual ~predicate() {}
67  virtual bool operator() ( T /*val*/ ) { return true; }
68  };
69 
70  // a false predicate
71  template <typename T>
72  class f_predicate: public predicate<T>
73  {
74  public:
75  virtual bool operator() ( T /*val*/ ) { return false; }
76  };
77 
78  // predefined predicate for validating
79  // a value between two values known at
80  // predicate initialization
81  template <typename T>
82  class btw_predicate: public predicate<T>
83  {
84  private:
85  T my_min;
86  T my_max;
87  bool inclusive;
88 
89  public:
90  btw_predicate( T new_min, T new_max, bool new_inclusive ): my_min( new_min ), my_max( new_max ), inclusive( new_inclusive ) {}
91 
92  bool operator() ( T val )
93  {
94  return ( ( inclusive )?( ( val >= my_min ) && ( val <= my_max ) ):( ( val > my_min ) && ( val < my_max ) ) );
95  }
96  };
97 
98  // predefined predicate for validating
99  // a value greater than a value known at
100  // predicate initialization
101  template <typename T>
102  class gt_predicate: public predicate<T>
103  {
104  private:
105  T my_min;
106  bool inclusive;
107 
108  public:
109  gt_predicate( T new_min, bool new_inclusive ): my_min( new_min ), inclusive( new_inclusive ) {}
110 
111  bool operator() ( T val )
112  {
113  return ( ( inclusive )?( ( val >= my_min ) ):( ( val > my_min ) ) );
114  }
115  };
116 
117  // predefined predicate for validating
118  // a value less than a value known at
119  // predicate initialization
120  template <typename T>
121  class lt_predicate: public predicate<T>
122  {
123  private:
124  T my_max;
125  bool inclusive;
126 
127  public:
128  lt_predicate( T new_max, bool new_inclusive ): my_max( new_max ), inclusive( new_inclusive ) {}
129 
130  bool operator() ( T val )
131  {
132  return ( ( inclusive )?( ( val <= my_max ) ):( ( val < my_max ) ) );
133  }
134  };
135 
136  // superclass for predicates needing
137  // agent state
138  template <typename T>
139  class agent_predicate: public predicate<T>
140  {
141  protected:
143 
144  public:
145  agent_predicate( agent *new_agent ): my_agent( new_agent ) {}
146  };
147 
148 
150  // Common for params, stats, timers, etc.
152 
154  {
155  private:
156  const char *name;
157 
158  public:
159  named_object( const char *new_name ): name( new_name ) {}
160  virtual ~named_object() {}
161 
162  //
163 
164  const char *get_name()
165  {
166  return name;
167  }
168 
169  //
170 
171  virtual char *get_string() = 0;
172  };
173 
174 
175  template <typename T>
176  class accumulator: public std::unary_function<T, void>
177  {
178  public:
179  virtual ~accumulator() {}
180 
181  virtual void operator() ( T /*val*/ ) {}
182  };
183 
184 
185  // this class provides for efficient
186  // string->object access
187  template <class T>
189  {
190  protected:
192  std::map<std::string, T *> *objects;
193 
194  void add( T *new_object )
195  {
196  std::string temp_str( new_object->get_name() );
197  (*objects)[ temp_str ] = new_object;
198  }
199 
200  public:
201  object_container( agent *new_agent ): my_agent( new_agent ), objects( new std::map<std::string, T *> ) {}
202 
204  {
205  typename std::map<std::string, T *>::iterator p;
206 
207  for ( p=objects->begin(); p!=objects->end(); p++ )
208  delete p->second;
209 
210  delete objects;
211  }
212 
213  //
214 
215  T *get( const char *name )
216  {
217  std::string temp_str( name );
218  typename std::map<std::string, T *>::iterator p = objects->find( temp_str );
219 
220  if ( p == objects->end() )
221  return NULL;
222  else
223  return p->second;
224  }
225 
227  {
228  typename std::map<std::string, T *>::iterator p;
229 
230  for ( p=objects->begin(); p!=objects->end(); p++ )
231  {
232  f( p->second );
233  }
234  }
235  };
236 
237 
239  // Parameters
241 
242  // all parameters have a name and
243  // can be manipulated generically
244  // via strings
245  class param: public named_object
246  {
247  public:
248  param( const char *new_name ): named_object( new_name ) {}
249  virtual ~param() {}
250 
251  //
252 
253  virtual bool set_string( const char *new_string ) = 0;
254  virtual bool validate_string( const char *new_string ) = 0;
255  };
256 
257 
258  // a primitive parameter can take any primitive
259  // data type as value and is validated via
260  // any unary predicate
261  template <typename T>
262  class primitive_param: public param
263  {
264  protected:
265  T value;
268 
269  public:
270  primitive_param( const char *new_name, T new_value, predicate<T> *new_val_pred, predicate<T> *new_prot_pred ): param( new_name ), value( new_value ), val_pred( new_val_pred ), prot_pred( new_prot_pred ) {}
271 
273  {
274  delete val_pred;
275  delete prot_pred;
276  }
277 
278  //
279 
280  virtual char *get_string()
281  {
282  std::string temp_str;
283  to_string( value, temp_str );
284  return strdup( temp_str.c_str() );
285  }
286 
287  virtual bool set_string( const char *new_string )
288  {
289  T new_val;
290  from_string( new_val, new_string );
291 
292  if ( !(*val_pred)( new_val ) || (*prot_pred)( new_val ) )
293  {
294  return false;
295  }
296  else
297  {
298  set_value( new_val );
299  return true;
300  }
301  }
302 
303  virtual bool validate_string( const char *new_string )
304  {
305  T new_val;
306  from_string( new_val, new_string );
307 
308  return (*val_pred)( new_val );
309  }
310 
311  //
312 
313  virtual T get_value()
314  {
315  return value;
316  }
317 
318  virtual void set_value( T new_value )
319  {
320  value = new_value;
321  }
322  };
323 
324  // these are easy definitions for int and double parameters
327 
328 
329  // a string param deals with character strings
330  class string_param: public param
331  {
332  protected:
333  std::string *value;
336 
337  public:
338  string_param( const char *new_name, const char *new_value, predicate<const char *> *new_val_pred, predicate<const char *> *new_prot_pred ): param( new_name ), value( new std::string( new_value ) ), val_pred( new_val_pred ), prot_pred( new_prot_pred ) {}
339 
340  virtual ~string_param()
341  {
342  delete value;
343  delete val_pred;
344  delete prot_pred;
345  }
346 
347  //
348 
349  virtual char *get_string()
350  {
351  char *return_val = new char[ value->length() + 1 ];
352  strcpy( return_val, value->c_str() );
353  return_val[ value->length() ] = '\0';
354 
355  return return_val;
356  }
357 
358  virtual bool set_string( const char *new_string )
359  {
360  if ( !(*val_pred)( new_string ) || (*prot_pred)( new_string ) )
361  {
362  return false;
363  }
364  else
365  {
366  set_value( new_string );
367  return true;
368  }
369  }
370 
371  virtual bool validate_string( const char *new_value )
372  {
373  return (*val_pred)( new_value );
374  }
375 
376  //
377 
378  virtual const char *get_value()
379  {
380  return value->c_str();
381  }
382 
383  virtual void set_value( const char *new_value )
384  {
385  value->assign( new_value );
386  }
387  };
388 
389  // a primitive_set param maintains a set of primitives
390  template <typename T>
392  {
393  protected:
394  std::set< T > *my_set;
395  std::string *value;
397 
398  public:
399  primitive_set_param( const char *new_name, predicate< T > *new_prot_pred ): param( new_name ), my_set( new std::set< T >() ), value( new std::string ), prot_pred( new_prot_pred ) {}
400 
402  {
403  delete my_set;
404  delete value;
405  delete prot_pred;
406  }
407 
408  virtual char *get_string()
409  {
410  char *return_val = new char[ value->length() + 1 ];
411  strcpy( return_val, value->c_str() );
412  return_val[ value->length() ] = '\0';
413 
414  return return_val;
415  }
416 
417  virtual bool validate_string( const char *new_value )
418  {
419  T test_val;
420 
421  return from_string( test_val, new_value );
422  }
423 
424  virtual bool set_string( const char *new_string )
425  {
426  T new_val;
427  from_string( new_val, new_string );
428 
429  if ( (*prot_pred)( new_val ) )
430  {
431  return false;
432  }
433  else
434  {
435  typename std::set< T >::iterator it = my_set->find( new_val );
436  std::string temp_str;
437 
438  if ( it != my_set->end() )
439  {
440  my_set->erase( it );
441 
442  // regenerate value from scratch
443  value->clear();
444  for ( it=my_set->begin(); it!=my_set->end(); )
445  {
446  to_string( *it, temp_str );
447  value->append( temp_str );
448 
449  it++;
450 
451  if ( it != my_set->end() )
452  value->append( ", " );
453  }
454  }
455  else
456  {
457  my_set->insert( new_val );
458 
459  if ( !value->empty() )
460  value->append( ", " );
461 
462  to_string( new_val, temp_str );
463  value->append( temp_str );
464  }
465 
466 
467  return true;
468  }
469  }
470 
471  virtual bool in_set( T test_val )
472  {
473  return ( my_set->find( test_val ) != my_set->end() );
474  }
475 
476  virtual typename std::set< T >::iterator set_begin()
477  {
478  return my_set->begin();
479  }
480 
481  virtual typename std::set< T >::iterator set_end()
482  {
483  return my_set->end();
484  }
485  };
486 
487  // these are easy definitions for sets
489 
490  // a sym_set param maintains a set of strings
491  class sym_set_param: public param
492  {
493  protected:
494  std::set<Symbol *> *my_set;
495  std::string *value;
497 
499 
500  public:
501  sym_set_param( const char *new_name, predicate<const char *> *new_prot_pred, agent *new_agent ): param( new_name ), my_set( new std::set<Symbol *>() ), value( new std::string ), prot_pred( new_prot_pred ), my_agent( new_agent ) {}
502 
503  virtual ~sym_set_param()
504  {
505  for ( std::set<Symbol *>::iterator p=my_set->begin(); p!=my_set->end(); p++ )
506  symbol_remove_ref( my_agent, (*p) );
507 
508  delete my_set;
509  delete value;
510  delete prot_pred;
511  }
512 
513  //
514 
515  virtual char *get_string()
516  {
517  char *return_val = new char[ value->length() + 1 ];
518  strcpy( return_val, value->c_str() );
519  return_val[ value->length() ] = '\0';
520 
521  return return_val;
522  }
523 
524  virtual bool set_string( const char *new_string )
525  {
526  if ( (*prot_pred)( new_string ) )
527  {
528  return false;
529  }
530  else
531  {
532  set_value( new_string );
533  return true;
534  }
535  }
536 
537  virtual bool validate_string( const char * /*new_value*/ )
538  {
539  return true;
540  }
541 
542  //
543 
544  virtual bool in_set( Symbol *test_sym )
545  {
546  bool return_val = false;
547 
548  if ( ( test_sym->common.symbol_type == SYM_CONSTANT_SYMBOL_TYPE ) ||
549  ( test_sym->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE ) ||
550  ( test_sym->common.symbol_type == FLOAT_CONSTANT_SYMBOL_TYPE ) )
551  {
552  Symbol *my_sym = test_sym;
553 
554  if ( my_sym->common.symbol_type != SYM_CONSTANT_SYMBOL_TYPE )
555  {
556  std::string temp_str;
557 
558  if ( my_sym->common.symbol_type == INT_CONSTANT_SYMBOL_TYPE )
559  {
560  to_string( my_sym->ic.value, temp_str );
561  }
562  else
563  {
564  to_string( my_sym->fc.value, temp_str );
565  }
566 
567  my_sym = make_sym_constant( my_agent, temp_str.c_str() );
568  }
569 
570  std::set<Symbol *>::iterator p = my_set->find( my_sym );
571  return_val = ( p != my_set->end() );
572 
573  if ( test_sym != my_sym )
574  {
575  symbol_remove_ref( my_agent, my_sym );
576  }
577  }
578 
579  return return_val;
580  }
581 
582  virtual void set_value( const char *new_value )
583  {
584  Symbol *my_sym = make_sym_constant( my_agent, new_value );
585  std::set<Symbol *>::iterator p = my_set->find( my_sym );
586 
587  if ( p != my_set->end() )
588  {
589  my_set->erase( p );
590 
591  // remove for now and when added to the set
592  symbol_remove_ref( my_agent, my_sym );
593  symbol_remove_ref( my_agent, my_sym );
594 
595  // regenerate value from scratch
596  value->clear();
597  for ( p=my_set->begin(); p!=my_set->end(); )
598  {
599  value->append( (*p)->sc.name );
600 
601  p++;
602 
603  if ( p != my_set->end() )
604  value->append( ", " );
605  }
606  }
607  else
608  {
609  my_set->insert( my_sym );
610 
611  if ( !value->empty() )
612  value->append( ", " );
613 
614  value->append( my_sym->sc.name );
615  }
616  }
617  };
618 
619  // a constant parameter deals in discrete values
620  // for efficiency, internally we use enums, elsewhere
621  // strings for user-readability
622  template <typename T>
623  class constant_param: public param
624  {
625  protected:
626  T value;
627  std::map<T, const char *> *value_to_string;
628  std::map<std::string, T> *string_to_value;
630 
631  public:
632  constant_param( const char *new_name, T new_value, predicate<T> *new_prot_pred ): param( new_name ), value( new_value ), value_to_string( new std::map<T, const char *>() ), string_to_value( new std::map<std::string, T> ), prot_pred( new_prot_pred ) {}
633 
634  virtual ~constant_param()
635  {
636  delete value_to_string;
637  delete string_to_value;
638  delete prot_pred;
639  }
640 
641  //
642 
643  virtual char *get_string()
644  {
645  typename std::map<T, const char *>::iterator p;
646  p = value_to_string->find( value );
647 
648  if ( p == value_to_string->end() )
649  return NULL;
650  else
651  {
652  size_t len = strlen( p->second );
653  char *return_val = new char[ len + 1 ];
654 
655  strcpy( return_val, p->second );
656  return_val[ len ] = '\0';
657 
658  return return_val;
659  }
660  }
661 
662  virtual bool set_string( const char *new_string )
663  {
664  typename std::map<std::string, T>::iterator p;
665  std::string temp_str( new_string );
666 
667  p = string_to_value->find( temp_str );
668 
669  if ( ( p == string_to_value->end() ) || (*prot_pred)( p->second ) )
670  {
671  return false;
672  }
673  else
674  {
675  set_value( p->second );
676  return true;
677  }
678  }
679 
680  virtual bool validate_string( const char *new_string )
681  {
682  typename std::map<std::string, T>::iterator p;
683  std::string temp_str( new_string );
684 
685  p = string_to_value->find( temp_str );
686 
687  return ( p != string_to_value->end() );
688  }
689 
690  //
691 
692  virtual T get_value()
693  {
694  return value;
695  }
696 
697  virtual void set_value( T new_value )
698  {
699  value = new_value;
700  }
701 
702  //
703 
704  virtual void add_mapping( T val, const char *str )
705  {
706  std::string my_string( str );
707 
708  // string to value
709  (*string_to_value)[ my_string ] = val;
710 
711  // value to string
712  (*value_to_string)[ val ] = str;
713  }
714  };
715 
716  // this is an easy implementation of a boolean parameter
717  enum boolean { off, on };
718  class boolean_param: public constant_param<boolean>
719  {
720  public:
721  boolean_param( const char *new_name, boolean new_value, predicate<boolean> *new_prot_pred ): constant_param<boolean>( new_name, new_value, new_prot_pred )
722  {
723  add_mapping( off, "off" );
724  add_mapping( on, "on" );
725  }
726  };
727 
728 
730  // Parameter Container
732 
734 
735 
737  // Statistics
739 
740  // all statistics have a name and
741  // can be retrieved generically
742  // via strings
743  class stat: public named_object
744  {
745  public:
746  stat( const char *new_name ): named_object( new_name ) {}
747  virtual ~stat() {}
748 
749  //
750 
751  virtual void reset() = 0;
752  };
753 
754 
755  // a primitive statistic can take any primitive
756  // data type as value
757  template <typename T>
758  class primitive_stat: public stat
759  {
760  private:
761  T value;
764 
765  public:
766  primitive_stat( const char *new_name, T new_value, predicate<T> *new_prot_pred ): stat( new_name ), value( new_value ), reset_val( new_value ), prot_pred( new_prot_pred ) {}
767 
768  virtual ~primitive_stat()
769  {
770  delete prot_pred;
771  }
772 
773  //
774 
775  virtual char *get_string()
776  {
777  T my_val = get_value();
778 
779  std::string temp_str;
780  to_string( my_val, temp_str );
781  return strdup(temp_str.c_str());
782  }
783 
784  void reset()
785  {
786  if ( !(*prot_pred)( value ) )
787  value = reset_val;
788  }
789 
790  //
791 
792  virtual T get_value()
793  {
794  return value;
795  }
796 
797  virtual void set_value( T new_value )
798  {
799  value = new_value;
800  }
801  };
802 
803  // these are easy definitions for int and double stats
806 
808  // Statistic Containers
810 
811  class stat_container: public object_container<stat>
812  {
813  public:
814  stat_container( agent *new_agent ): object_container<stat>( new_agent ) {}
815 
816  //
817 
818  void reset()
819  {
820  for ( std::map<std::string, stat *>::iterator p=objects->begin(); p!=objects->end(); p++ )
821  p->second->reset();
822  }
823  };
824 
825 
827  // timers
829 
830  class timer: public named_object
831  {
832  public:
834 
835  protected:
837 
838  soar_process_timer stopwatch;
839  soar_timer_accumulator accumulator;
840 
843 
844  public:
845 
846  timer( const char *new_name, agent *new_agent, timer_level new_level, predicate<timer_level> *new_pred, bool soar_control = true );
847 
848  virtual ~timer()
849  {
850  delete pred;
851  }
852 
853  //
854 
855  virtual char *get_string()
856  {
857  double my_value = value();
858 
859  std::string temp_str;
860  to_string( my_value, temp_str );
861  return strdup(temp_str.c_str());
862  }
863 
864  //
865 
866  virtual void reset()
867  {
868  stopwatch.stop();
869  accumulator.reset();
870  }
871 
872  virtual double value()
873  {
874  return accumulator.get_sec();
875  }
876 
877  //
878 
879  virtual void start()
880  {
881  if ( (*pred)( level ) )
882  {
883  stopwatch.start();
884  }
885  }
886 
887  virtual void stop()
888  {
889  if ( (*pred)( level ) )
890  {
891  stopwatch.stop();
892  accumulator.update(stopwatch);
893  }
894  }
895  };
896 
897 
899  // Timer Containers
901 
902  class timer_container: public object_container<timer>
903  {
904  public:
905  timer_container( agent *new_agent ): object_container<timer>( new_agent ) {}
906 
907  //
908 
909  void reset()
910  {
911  for ( std::map<std::string, timer *>::iterator p=objects->begin(); p!=objects->end(); p++ )
912  p->second->reset();
913  }
914  };
915 
916 
918  // Memory Pool Allocators
920 
921 #define USE_MEM_POOL_ALLOCATORS 1
922 
923 #ifdef USE_MEM_POOL_ALLOCATORS
924 
925  memory_pool* get_memory_pool( agent* my_agent, size_t size );
926 
927  template <class T>
929  {
930  public:
931  typedef T value_type;
932  typedef size_t size_type;
933  typedef ptrdiff_t difference_type;
934 
935  typedef T* pointer;
936  typedef const T* const_pointer;
937 
938  typedef T& reference;
939  typedef const T& const_reference;
940 
941  public:
942  agent* get_agent() const { return my_agent; }
943 
944  soar_memory_pool_allocator( agent* new_agent ): my_agent(new_agent), mem_pool(NULL), size(sizeof(value_type))
945  {
946  // useful for debugging
947  // std::string temp_this( typeid( value_type ).name() );
948  }
949 
951  {
952  // useful for debugging
953  // std::string temp_this( typeid( value_type ).name() );
954  }
955 
956  template <class _other>
958  {
959  // useful for debugging
960  // std::string temp_this( typeid( T ).name() );
961  // std::string temp_other( typeid( _other ).name() );
962  }
963 
965 #ifndef NDEBUG
966  n
967 #endif
968  , const void* = 0 )
969  {
970  assert( n == 1 );
971 
972  if ( !mem_pool )
973  {
975  }
976 
977  pointer t;
978  allocate_with_pool( my_agent, mem_pool, &t );
979 
980  return t;
981  }
982 
983  void deallocate( void* p, size_type
984 #ifndef NDEBUG
985  n
986 #endif
987  )
988  {
989  assert( n == 1 );
990 
991  // not sure if this is correct...
992  // it only comes up if an object uses another object's
993  // allocator to deallocate memory that it allocated.
994  // it's quite possible, then, that the sizes would be off
995  if ( !mem_pool )
996  {
998  }
999 
1000  if ( p )
1001  {
1002  free_with_pool( mem_pool, p );
1003  }
1004  }
1005 
1007  {
1008  new (p) T( val );
1009  }
1010 
1011  void destroy( pointer p )
1012  {
1013  p->~T();
1014  }
1015 
1017  {
1018  return static_cast< size_type >( -1 );
1019  }
1020 
1022  {
1023  return &r;
1024  }
1025 
1027  {
1028  return &r;
1029  }
1030 
1031  template <class U>
1032  struct rebind
1033  {
1035  };
1036 
1037 
1038  private:
1042 
1044 
1045  };
1046 
1047 #endif
1048 
1050  // Object Store Management
1051  //
1052  // Model:
1053  // 1) Store consists of a set of "objects"
1054  // 2) Time proceeds forward in discrete "steps"
1055  // 3) Objects decay according to arbitrary decay function
1056  // 4) Object references may occur multiple times within each step
1057  //
1058  // Implementation:
1059  // A) Templated object store (internally maintains pointers to type T)
1060  // B) Bounded history (template parameter N)
1061  // C) Subclasses implement decay
1063 
1064  template <class T, int N>
1066  {
1067  public:
1068  typedef uint64_t time_step;
1069  typedef uint64_t object_reference;
1070 
1071  typedef std::set< const T* > object_set;
1072 
1073  protected:
1075  {
1079 
1080  typedef struct object_history_struct
1081  {
1083  unsigned int next_p;
1084  unsigned int history_ct;
1085 
1089 
1091 
1093 
1094  //
1095 
1096  const T* this_object;
1097 
1098  //
1099 
1100  object_history_struct( const T* obj )
1101  {
1102  this_object = obj;
1103 
1104  buffered_references = 0;
1105 
1106  decay_step = 0;
1107 
1108  history_references = 0;
1109  total_references = 0;
1110  first_reference = 0;
1111 
1112  next_p = 0;
1113  history_ct = 0;
1114  for ( int i=0; i<N; i++ )
1115  {
1117  reference_history[ i ].t_step = 0;
1118  }
1119  }
1120 
1121  } object_history;
1122 
1123  unsigned int history_next( unsigned int current )
1124  {
1125  return ( ( current == ( N - 1 ) )?( 0 ):( current + 1 ) );
1126  }
1127 
1128  unsigned int history_prev( unsigned int current )
1129  {
1130  return ( ( current == 0 )?( N - 1 ):( current - 1 ) );
1131  }
1132 
1133  private:
1134  typedef std::map< const T*, object_history > object_history_map;
1135  typedef std::set< object_history* > history_set;
1136  typedef std::set< time_step > time_set;
1137  typedef std::map< time_step, history_set > forgetting_map;
1138 
1139  protected:
1140  const object_history* get_history( const T* obj )
1141  {
1142  typename object_history_map::iterator p = object_histories.find( obj );
1143  if ( p != object_histories.end() )
1144  {
1145  return &( p->second );
1146  }
1147  else
1148  {
1149  return NULL;
1150  }
1151  }
1152 
1154  {
1155  return step_count;
1156  }
1157 
1159  {
1160  return initialized;
1161  }
1162 
1163  virtual time_step estimate_forgetting_time( const object_history* h, time_step t, bool fresh_reference ) = 0;
1164  virtual bool should_forget( const object_history* h, time_step t ) = 0;
1165 
1166  virtual void _init() = 0;
1167  virtual void _down() = 0;
1168 
1169  public:
1171  {
1172  }
1173 
1174  void initialize()
1175  {
1176  if ( !initialized )
1177  {
1178  step_count = 1;
1179 
1180  _init();
1181 
1182  initialized = true;
1183  }
1184  }
1185 
1186  void teardown()
1187  {
1188  if ( initialized )
1189  {
1190  touched_histories.clear();
1191  touched_times.clear();
1192  forgetting_pq.clear();
1193  forgotten.clear();
1194  object_histories.clear();
1195 
1196  _down();
1197 
1198  initialized = false;
1199  }
1200  }
1201 
1202  // return: was this a new object?
1203  bool reference_object( const T* obj, object_reference num )
1204  {
1205  object_history* h = NULL;
1206  bool return_val = false;
1207 
1208  typename object_history_map::iterator p = object_histories.find( obj );
1209  if ( p != object_histories.end() )
1210  {
1211  h = &( p->second );
1212  }
1213  else
1214  {
1215  std::pair< typename object_history_map::iterator, bool > ip = object_histories.insert( std::make_pair< const T*, object_history >( obj, object_history( obj ) ) );
1216  assert( ip.second );
1217 
1218  h = &( ip.first->second );
1219 
1220  return_val = true;
1221  }
1222 
1223  h->buffered_references += num;
1224  touched_histories.insert( h );
1225 
1226  return return_val;
1227  }
1228 
1229  void remove_object( const T* obj )
1230  {
1231  typename object_history_map::iterator p = object_histories.find( obj );
1232  if ( p != object_histories.end() )
1233  {
1234  touched_histories.erase( &( p->second ) );
1235  remove_from_pq( &( p->second ) );
1236  object_histories.erase( p );
1237  }
1238  }
1239 
1241  {
1242  typename history_set::iterator h_p;
1243  object_history* h;
1244 
1245  // add to history for changed histories
1246  for ( h_p=touched_histories.begin(); h_p!=touched_histories.end(); h_p++ )
1247  {
1248  h = *h_p;
1249 
1250  // update number of references in the current history
1251  // (has to come before history overwrite)
1253 
1254  // set history
1257 
1258  // keep track of first reference
1259  if ( h->total_references == 0 )
1260  {
1262  }
1263 
1264  // update counters
1265  if ( h->history_ct < N )
1266  {
1267  h->history_ct++;
1268  }
1269  h->next_p = history_next( h->next_p );
1271 
1272  // reset buffer counter
1273  h->buffered_references = 0;
1274 
1275  // update p-queue
1276  if ( h->decay_step != 0 )
1277  {
1279  }
1280  else
1281  {
1282  add_to_pq( h, estimate_forgetting_time( h, step_count, true ) );
1283  }
1284  }
1285 
1286  touched_histories.clear();
1287  }
1288 
1289  typename object_set::iterator forgotten_begin()
1290  {
1291  return forgotten.begin();
1292  }
1293 
1294  typename object_set::iterator forgotten_end()
1295  {
1296  return forgotten.end();
1297  }
1298 
1299  void forget()
1300  {
1301  forgotten.clear();
1302 
1303  if ( !forgetting_pq.empty() )
1304  {
1305  typename forgetting_map::iterator pq_p = forgetting_pq.begin();
1306 
1307  // check if we even have to do anything this time step
1308  if ( pq_p->first == step_count )
1309  {
1310  typename history_set::iterator d_p=pq_p->second.begin();
1311  typename history_set::iterator current_p;
1312 
1313  while ( d_p != pq_p->second.end() )
1314  {
1315  current_p = d_p++;
1316 
1317  if ( should_forget( *current_p, step_count ) )
1318  {
1319  forgotten.insert( (*current_p)->this_object );
1320  remove_from_pq( *current_p );
1321  }
1322  else
1323  {
1324  move_in_pq( *current_p, estimate_forgetting_time( *current_p, step_count, false ) );
1325  }
1326  }
1327 
1328  // clean up set
1329  touched_times.insert( pq_p->first );
1330  pq_p->second.clear();
1331  }
1332 
1333  // clean up touched time sets
1334  for ( time_set::iterator t_p=touched_times.begin(); t_p!=touched_times.end(); t_p++ )
1335  {
1336  pq_p = forgetting_pq.find( *t_p );
1337  if ( ( pq_p != forgetting_pq.end() ) && pq_p->second.empty() )
1338  {
1339  forgetting_pq.erase( pq_p );
1340  }
1341  }
1342 
1343  touched_times.clear();
1344  }
1345  }
1346 
1348  {
1349  step_count++;
1350  }
1351 
1352  void time_back()
1353  {
1354  step_count--;
1355  }
1356 
1357  private:
1358 
1360  {
1361  assert( h->decay_step == 0 );
1362 
1363  h->decay_step = t;
1364  forgetting_pq[ t ].insert( h );
1365  }
1366 
1368  {
1369  if ( h->decay_step )
1370  {
1371  typename forgetting_map::iterator f_p = forgetting_pq.find( h->decay_step );
1372  if ( f_p != forgetting_pq.end() )
1373  {
1374  f_p->second.erase( h );
1375  touched_times.insert( h->decay_step );
1376  }
1377 
1378  h->decay_step = 0;
1379  }
1380  }
1381 
1383  {
1384  if ( h->decay_step != new_t )
1385  {
1386  remove_from_pq( h );
1387  add_to_pq( h, new_t );
1388  }
1389  }
1390 
1392 
1394 
1399 
1401  };
1402 
1404  // Base-Level Activation (BLA) Object Store Management
1405  //
1406  // Notes:
1407  // - Approximation of decay time depends upon an estimate of
1408  // max reference/time step (template parameter R)
1409  // - Smallest activation is bounded by activation_low constant
1411 
1412  template <class T, int N, unsigned int R>
1413  class bla_object_memory : public object_memory<T,N>
1414  {
1415  protected:
1416  // helps avoid verbose types below
1420 
1421  private:
1425 
1427  double decay_rate;
1430 
1431  public:
1432  bla_object_memory(): activation_none( 1.0 ), activation_low( -1000000000 ), time_sum_none( 2.71828182845905 ), use_petrov( true ), decay_rate( -0.5 ), decay_thresh( -2.0 ), pow_cache_bound( 10 )
1433  {
1434  }
1435 
1436  // return: was the setting accepted?
1437  bool set_petrov( bool new_petrov )
1438  {
1439  if ( !this->is_initialized() )
1440  {
1441  use_petrov = new_petrov;
1442  return true;
1443  }
1444 
1445  return false;
1446  }
1447 
1448  // takes positive, stores negative
1449  // return: was the value accepted (0, 1)
1450  bool set_decay_rate( double new_decay_rate )
1451  {
1452  if ( ( new_decay_rate > 0 ) && ( new_decay_rate < 1 ) && !this->is_initialized() )
1453  {
1454  decay_rate = -new_decay_rate;
1455  return true;
1456  }
1457 
1458  return false;
1459  }
1460 
1461  // return: was the setting accepted?
1462  bool set_decay_thresh( double new_decay_thresh )
1463  {
1464  if ( !this->is_initialized() )
1465  {
1466  decay_thresh = new_decay_thresh;
1467  return true;
1468  }
1469 
1470  return false;
1471  }
1472 
1473  // input: cache size in megabytes (0, inf)
1474  // return: was the setting accepted?
1475  bool set_pow_cache_bound( uint64_t new_pow_cache_bound )
1476  {
1477  if ( ( new_pow_cache_bound > 0 ) && !this->is_initialized() )
1478  {
1479  pow_cache_bound = new_pow_cache_bound;
1480  return true;
1481  }
1482 
1483  return false;
1484  }
1485 
1486  double get_object_activation( T* obj, bool log_result )
1487  {
1488  return compute_history_activation( get_history( obj ), this->get_current_time(), log_result );
1489  }
1490 
1491  protected:
1492  void _init()
1493  {
1494  // Pre-compute the integer powers of the decay exponent in order to avoid
1495  // repeated calls to pow() at runtime
1496  {
1497  // determine cache size
1498  {
1499  // computes how many powers to compute
1500  // basic idea: solve for the time that would just fall below the decay threshold, given decay rate and assumption of max references/time step
1501  // t = e^( ( thresh - ln( max_refs ) ) / -decay_rate )
1502  double cache_full = static_cast<double>( exp( ( decay_thresh - log( static_cast<double>( R ) ) ) / decay_rate ) );
1503 
1504  // we bound this by the max-pow-cache parameter to control the space vs. time tradeoff the cache supports
1505  // max-pow-cache is in MB, so do the conversion:
1506  // MB * 1024 bytes/KB * 1024 KB/MB
1507  double cache_bound_unit = ( static_cast<unsigned int>( pow_cache_bound * 1024 * 1024 ) / static_cast<unsigned int>( sizeof( double ) ) );
1508 
1509  pow_cache_size = static_cast< unsigned int >( ceil( ( cache_full > cache_bound_unit )?( cache_bound_unit ):( cache_full ) ) );
1510  }
1511 
1512  pow_cache = new double[ pow_cache_size ];
1513 
1514  pow_cache[0] = 0.0;
1515  for( unsigned int i=1; i<pow_cache_size; i++ )
1516  {
1517  pow_cache[ i ] = pow( static_cast<double>( i ), decay_rate );
1518  }
1519  }
1520 
1521  // calculate the pre-log'd forgetting threshold, to avoid most
1522  // calls to log
1523  decay_thresh_exp = exp( decay_thresh );
1524 
1525  // approximation cache
1526  {
1527  approx_cache[0] = 0;
1528  for ( int i=1; i<R; i++ )
1529  {
1530  approx_cache[i] = static_cast< time_step >( ceil( exp( static_cast<double>( decay_thresh - log( static_cast<double>(i) ) ) / static_cast<double>( decay_rate ) ) ) );
1531  }
1532  }
1533  }
1534 
1535  void _down()
1536  {
1537  // release power array memory
1538  delete[] pow_cache;
1539  }
1540 
1541  time_step estimate_forgetting_time( const object_history* h, time_step t, bool fresh_reference )
1542  {
1543  time_step return_val = t;
1544 
1545  // if new reference, we can cheaply under-estimate decay time
1546  // by treating all reference time steps independently
1547  // see AAAI FS: (Derbinsky & Laird 2011)
1548  if ( fresh_reference )
1549  {
1550  time_step to_add = 0;
1551 
1552  unsigned int p = h->next_p;
1553  unsigned int counter = h->history_ct;
1554  time_step t_diff = 0;
1555  object_reference approx_ref;
1556 
1557  while ( counter )
1558  {
1559  p = this->history_prev( p );
1560 
1561  t_diff = ( return_val - h->reference_history[ p ].t_step );
1562 
1563  approx_ref = ( ( h->reference_history[ p ].num_references < R )?( h->reference_history[ p ].num_references ):( R-1 ) );
1564  if ( approx_cache[ approx_ref ] > t_diff )
1565  {
1566  to_add += ( approx_cache[ approx_ref ] - t_diff );
1567  }
1568 
1569  counter--;
1570  }
1571 
1572  return_val += to_add;
1573  }
1574 
1575  // if approximation wasn't useful, or we used it previously and are now
1576  // beyond the underestimate, use binary parameter search to exactly
1577  // compute the time of forgetting
1578  if ( return_val == t )
1579  {
1580  time_step to_add = 1;
1581 
1582  if ( !should_forget( h, ( return_val + to_add ) ) )
1583  {
1584  // find absolute upper bound
1585  do
1586  {
1587  to_add *= 2;
1588  } while ( !should_forget( h, ( return_val + to_add ) ) );
1589 
1590  // vanilla binary search within range: (upper/2, upper)
1591  time_step upper_bound = to_add;
1592  time_step lower_bound, mid;
1593  if ( to_add < 4 )
1594  {
1595  lower_bound = upper_bound;
1596  }
1597  else
1598  {
1599  lower_bound = ( to_add / 2 );
1600  }
1601 
1602  while ( lower_bound != upper_bound )
1603  {
1604  mid = ( ( lower_bound + upper_bound ) / 2 );
1605 
1606  if ( should_forget( h, ( return_val + mid ) ) )
1607  {
1608  upper_bound = mid;
1609 
1610  if ( upper_bound - lower_bound <= 1 )
1611  {
1612  lower_bound = mid;
1613  }
1614  }
1615  else
1616  {
1617  lower_bound = mid;
1618 
1619  if ( upper_bound - lower_bound <= 1 )
1620  {
1621  lower_bound = upper_bound;
1622  }
1623  }
1624  }
1625 
1626  to_add = upper_bound;
1627  }
1628 
1629  return_val += to_add;
1630  }
1631 
1632  return return_val;
1633  }
1634 
1636  {
1637  return ( compute_history_activation( h, t, false ) < decay_thresh_exp );
1638  }
1639 
1640  private:
1641  double _pow( time_step t_diff )
1642  {
1643  if ( t_diff < pow_cache_size )
1644  {
1645  return pow_cache[ t_diff ];
1646  }
1647  else
1648  {
1649  return pow( static_cast<double>( t_diff ), decay_rate );
1650  }
1651  }
1652 
1653  double compute_history_activation( const object_history* h, time_step t, bool log_result )
1654  {
1655  double return_val = ( ( log_result )?( activation_none ):( time_sum_none ) );
1656 
1657  if ( h && h->history_ct )
1658  {
1659  return_val = 0.0;
1660 
1661  // sum history
1662  {
1663  unsigned int p = h->next_p;
1664  unsigned int counter = h->history_ct;
1665  time_step t_diff = 0;
1666 
1667  //
1668 
1669  while ( counter )
1670  {
1671  p = this->history_prev( p );
1672 
1673  t_diff = ( t - h->reference_history[ p ].t_step );
1674  assert( t_diff > 0 );
1675 
1676  return_val += ( h->reference_history[ p ].num_references * _pow( t_diff ) );
1677 
1678  counter--;
1679  }
1680 
1681  // tail approximation for a bounded history, see (Petrov 2006)
1682  if ( use_petrov )
1683  {
1684  // if ( n > k )
1685  if ( h->total_references > h->history_references )
1686  {
1687  // ( n - k ) * ( tn^(1-d) - tk^(1-d) )
1688  // -----------------------------------
1689  // ( 1 - d ) * ( tn - tk )
1690 
1691  // decay_rate is negated (for nice printing)
1692  double d_inv = ( 1 + decay_rate );
1693 
1694  return_val += ( ( ( h->total_references - h->history_references ) * ( pow( static_cast<double>( t - h->first_reference ), d_inv ) - pow( static_cast<double>( t_diff ), d_inv ) ) ) /
1695  ( d_inv * ( ( t - h->first_reference ) - t_diff ) ) );
1696  }
1697  }
1698  }
1699 
1700  if ( log_result )
1701  {
1702  if ( return_val > 0.0 )
1703  {
1704  return_val = log( return_val );
1705  if ( return_val < activation_low )
1706  {
1707  return_val = activation_low;
1708  }
1709  }
1710  else
1711  {
1712  return_val = activation_low;
1713  }
1714  }
1715  }
1716 
1717  return return_val;
1718  }
1719 
1721 
1722  unsigned int pow_cache_size;
1723  double* pow_cache;
1724 
1726  };
1727 
1728 }
1729 
1730 #endif