Ipopt Documentation  
IpCachedResults.hpp
Go to the documentation of this file.
1 // Copyright (C) 2004, 2011 International Business Machines and others.
2 // All Rights Reserved.
3 // This code is published under the Eclipse Public License.
4 //
5 // Authors: Carl Laird, Andreas Waechter IBM 2004-08-13
6 
7 #ifndef __IPCACHEDRESULTS_HPP__
8 #define __IPCACHEDRESULTS_HPP__
9 
10 #include "IpTaggedObject.hpp"
11 #include "IpObserver.hpp"
12 #include <algorithm>
13 #include <vector>
14 #include <list>
15 
16 namespace Ipopt
17 {
18 
19 #if IPOPT_CHECKLEVEL > 2
20 # define IP_DEBUG_CACHE
21 #endif
22 #ifdef IP_DEBUG_CACHE
23 # include "IpDebug.hpp"
24 #endif
25 
26 // Forward Declarations
27 
28 template<class T>
29 class DependentResult;
30 
31 // AW: I'm taking this out, since this is by far the most used
32 // class. We should keep it as simple as possible.
33 // /** Cache Priority Enum */
34 // enum CachePriority
35 // {
36 // CP_Lowest,
37 // CP_Standard,
38 // CP_Trial,
39 // CP_Iterate
40 // };
41 
67 template<class T>
69 {
70 public:
71 #ifdef IP_DEBUG_CACHE
73  static const Index dbg_verbosity;
74 #endif
75 
78 
80  Int max_cache_size
81  );
82 
84  virtual ~CachedResults();
86 
89 
93  const T& result,
94  const std::vector<const TaggedObject*>& dependents,
95  const std::vector<Number>& scalar_dependents
96  );
97 
103  T& retResult,
104  const std::vector<const TaggedObject*>& dependents,
105  const std::vector<Number>& scalar_dependents
106  ) const;
107 
110  const T& result,
111  const std::vector<const TaggedObject*>& dependents
112  );
113 
116  T& retResult,
117  const std::vector<const TaggedObject*>& dependents
118  ) const;
120 
125 
129  const T& result,
130  const TaggedObject* dependent1
131  );
132 
137  T& retResult,
138  const TaggedObject* dependent1
139  );
140 
145  const T& result,
146  const TaggedObject* dependent1,
147  const TaggedObject* dependent2
148  );
149 
154  T& retResult,
155  const TaggedObject* dependent1,
156  const TaggedObject* dependent2
157  );
158 
163  const T& result,
164  const TaggedObject* dependent1,
165  const TaggedObject* dependent2,
166  const TaggedObject* dependent3
167  );
168 
173  T& retResult,
174  const TaggedObject* dependent1,
175  const TaggedObject* dependent2,
176  const TaggedObject* dependent3
177  );
178 
182  T& retResult,
183  const TaggedObject& dependent1
184  )
185  {
186  return GetCachedResult1Dep(retResult, &dependent1);
187  }
188 
190  T& retResult,
191  const TaggedObject& dependent1,
192  const TaggedObject& dependent2
193  )
194  {
195  return GetCachedResult2Dep(retResult, &dependent1, &dependent2);
196  }
197 
199  T& retResult,
200  const TaggedObject& dependent1,
201  const TaggedObject& dependent2,
202  const TaggedObject& dependent3)
203  {
204  return GetCachedResult3Dep(retResult, &dependent1, &dependent2, &dependent3);
205  }
206 
208  const T& result,
209  const TaggedObject& dependent1
210  )
211  {
212  AddCachedResult1Dep(result, &dependent1);
213  }
214 
216  const T& result,
217  const TaggedObject& dependent1,
218  const TaggedObject& dependent2
219  )
220  {
221  AddCachedResult2Dep(result, &dependent1, &dependent2);
222  }
223 
225  const T& result,
226  const TaggedObject& dependent1,
227  const TaggedObject& dependent2,
228  const TaggedObject& dependent3
229  )
230  {
231  AddCachedResult3Dep(result, &dependent1, &dependent2, &dependent3);
232  }
234 
242  const std::vector<const TaggedObject*>& dependents,
243  const std::vector<Number>& scalar_dependents
244  );
245 
247  void Clear();
248 
250  void Clear(
251  Int max_cache_size
252  );
253 
254 private:
265 
267 
270  const CachedResults&
271  );
272 
274  void operator=(
275  const CachedResults&
276  );
278 
281 
283  mutable std::list<DependentResult<T>*>* cached_results_;
284 
290 
293 };
294 
300 template<class T>
302 {
303 public:
304 
305 #ifdef IP_DEBUG_CACHE
306  static const Index dbg_verbosity;
307 #endif
308 
311 
313  const T& result,
314  const std::vector<const TaggedObject*>& dependents,
315  const std::vector<Number>& scalar_dependents
316  );
317 
321 
324 
325  bool IsStale() const;
326 
328  void Invalidate();
329 
331  const T& GetResult() const;
333 
338  bool DependentsIdentical(
339  const std::vector<const TaggedObject*>& dependents,
340  const std::vector<Number>& scalar_dependents
341  ) const;
342 
344  void DebugPrint() const;
345 
346 protected:
356  virtual void ReceiveNotification(
357  NotifyType notify_type,
358  const Subject* subject
359  );
360 
361 private:
362 
373 
375 
378  const DependentResult&
379  );
380 
382  void operator=(
383  const DependentResult&
384  );
386 
392  bool stale_;
394  const T result_;
396  std::vector<TaggedObject::Tag> dependent_tags_;
398  std::vector<Number> scalar_dependents_;
399 };
400 
401 #ifdef IP_DEBUG_CACHE
402 template <class T>
404 
405 template <class T>
407 #endif
408 
409 template<class T>
411  const T& result,
412  const std::vector<const TaggedObject*>& dependents,
413  const std::vector<Number>& scalar_dependents
414 )
415  : stale_(false),
416  result_(result),
417  dependent_tags_(dependents.size()),
418  scalar_dependents_(scalar_dependents)
419 {
420 #ifdef IP_DEBUG_CACHE
421  DBG_START_METH("DependentResult<T>::DependentResult()", dbg_verbosity);
422 #endif
423 
424  for( Index i = 0; i < (Index) dependents.size(); ++i )
425  {
426  if( dependents[i] )
427  {
428  // Call the RequestAttach method of the Observer base class.
429  // This will add this dependent result in the Observer list
430  // for the Subject dependents[i]. As a consequence, the
431  // ReceiveNotification method of this DependentResult will be
432  // called with notify_type=NT_Changed, whenever the
433  // TaggedResult dependents[i] is changed (i.e. its HasChanged
434  // method is called).
435  RequestAttach(NT_Changed, dependents[i]);
436  dependent_tags_[i] = dependents[i]->GetTag();
437  }
438  else
439  {
440  dependent_tags_[i] = 0;
441  }
442  }
443 }
444 
445 template<class T>
447 {
448 #ifdef IP_DEBUG_CACHE
449  DBG_START_METH("DependentResult<T>::~DependentResult()", dbg_verbosity);
450  //DBG_ASSERT(stale_ == true);
451 #endif
452  // Nothing to be done here, destructor
453  // of T should sufficiently remove
454  // any memory, etc.
455 }
456 
457 template<class T>
459 {
460  return stale_;
461 }
462 
463 template<class T>
465 {
466  stale_ = true;
467 }
468 
469 template<class T>
471  NotifyType notify_type,
472  const Subject* /*subject*/
473 )
474 {
475 #ifdef IP_DEBUG_CACHE
476  DBG_START_METH("DependentResult<T>::ReceiveNotification", dbg_verbosity);
477 #endif
478 
479  if( notify_type == NT_Changed || notify_type == NT_BeingDestroyed )
480  {
481  stale_ = true;
482  // technically, I could unregister the notifications here, but they
483  // aren't really hurting anything
484  }
485 }
486 
487 template<class T>
489  const std::vector<const TaggedObject*>& dependents,
490  const std::vector<Number>& scalar_dependents
491 ) const
492 {
493 #ifdef IP_DEBUG_CACHE
494  DBG_START_METH("DependentResult<T>::DependentsIdentical", dbg_verbosity);
495  DBG_ASSERT(stale_ == false);
496  DBG_ASSERT(dependents.size() == dependent_tags_.size());
497 #endif
498 
499  bool retVal = true;
500 
501  if( dependents.size() != dependent_tags_.size() || scalar_dependents.size() != scalar_dependents_.size() )
502  {
503  retVal = false;
504  }
505  else
506  {
507  for( Index i = 0; i < (Index) dependents.size(); i++ )
508  {
509  if( ( dependents[i] && dependents[i]->GetTag() != dependent_tags_[i])
510  || (!dependents[i] && dependent_tags_[i] != 0) )
511  {
512  retVal = false;
513  break;
514  }
515  }
516  if( retVal )
517  for( Index i = 0; i < (Index) scalar_dependents.size(); i++ )
518  if( scalar_dependents[i] != scalar_dependents_[i] )
519  {
520  retVal = false;
521  break;
522  }
523  }
524 
525  return retVal;
526 }
527 
528 template<class T>
530 {
531 #ifdef IP_DEBUG_CACHE
532  DBG_START_METH("DependentResult<T>::GetResult()", dbg_verbosity);
533  DBG_ASSERT(stale_ == false);
534 #endif
535 
536  return result_;
537 }
538 
539 template<class T>
541 {
542 #ifdef IP_DEBUG_CACHE
543  DBG_START_METH("DependentResult<T>::DebugPrint", dbg_verbosity);
544 #endif
545 
546 }
547 
548 template<class T>
550  Int max_cache_size
551 )
552  : max_cache_size_(max_cache_size),
553  cached_results_(NULL)
554 {
555 #ifdef IP_DEBUG_CACHE
556  DBG_START_METH("CachedResults<T>::CachedResults", dbg_verbosity);
557 #endif
558 
559 }
560 
561 template<class T>
563 {
564 #ifdef IP_DEBUG_CACHE
565  DBG_START_METH("CachedResults<T>::!CachedResults()", dbg_verbosity);
566 #endif
567 
568  if( cached_results_ )
569  {
570  for( typename std::list<DependentResult<T>*>::iterator iter = cached_results_->begin(); iter != cached_results_->end(); iter++ )
571  {
572  delete *iter;
573  }
574 
575  delete cached_results_;
576  }
577  /*
578  while (!cached_results_.empty()) {
579  DependentResult<T>* result = cached_results_.back();
580  cached_results_.pop_back();
581  delete result;
582  }
583  */
584 }
585 
586 template<class T>
588  const T& result,
589  const std::vector<const TaggedObject*>& dependents,
590  const std::vector<Number>& scalar_dependents
591 )
592 {
593 #ifdef IP_DEBUG_CACHE
594  DBG_START_METH("CachedResults<T>::AddCachedResult", dbg_verbosity);
595 #endif
596 
597  CleanupInvalidatedResults();
598 
599  // insert the new one here
600  DependentResult<T>* newResult = new DependentResult<T>(result, dependents, scalar_dependents);
601  if( !cached_results_ )
602  {
603  cached_results_ = new std::list<DependentResult<T>*>;
604  }
605 
606  cached_results_->push_front(newResult);
607 
608  // keep the list small enough
609  if( max_cache_size_ >= 0 )
610  {
611  // if negative, allow infinite cache
612  // non-negative - limit size of list to max_cache_size
613  DBG_ASSERT((Int)cached_results_->size() <= max_cache_size_ + 1);
614  if( (Int) cached_results_->size() > max_cache_size_ )
615  {
616  delete cached_results_->back();
617  cached_results_->pop_back();
618  }
619  }
620 
621 #ifdef IP_DEBUG_CACHE
622  DBG_EXEC(2, DebugPrintCachedResults());
623 #endif
624 
625 }
626 
627 template<class T>
629  const T& result,
630  const std::vector<const TaggedObject*>& dependents
631 )
632 {
633  std::vector<Number> scalar_dependents;
634  AddCachedResult(result, dependents, scalar_dependents);
635 }
636 
637 template<class T>
639  T& retResult,
640  const std::vector<const TaggedObject*>& dependents,
641  const std::vector<Number>& scalar_dependents
642 ) const
643 {
644 #ifdef IP_DEBUG_CACHE
645  DBG_START_METH("CachedResults<T>::GetCachedResult", dbg_verbosity);
646 #endif
647 
648  if( !cached_results_ )
649  {
650  return false;
651  }
652 
653  CleanupInvalidatedResults();
654 
655  bool retValue = false;
656  typename std::list<DependentResult<T>*>::const_iterator iter;
657  for( iter = cached_results_->begin(); iter != cached_results_->end(); iter++ )
658  if( (*iter)->DependentsIdentical(dependents, scalar_dependents) )
659  {
660  retResult = (*iter)->GetResult();
661  retValue = true;
662  break;
663  }
664 
665 #ifdef IP_DEBUG_CACHE
666  DBG_EXEC(2, DebugPrintCachedResults());
667 #endif
668 
669  return retValue;
670 }
671 
672 template<class T>
674  T& retResult,
675  const std::vector<const TaggedObject*>& dependents
676 ) const
677 {
678  std::vector<Number> scalar_dependents;
679  return GetCachedResult(retResult, dependents, scalar_dependents);
680 }
681 
682 template<class T>
684  const T& result,
685  const TaggedObject* dependent1
686 )
687 {
688 #ifdef IP_DEBUG_CACHE
689  DBG_START_METH("CachedResults<T>::AddCachedResult1Dep", dbg_verbosity);
690 #endif
691 
692  std::vector<const TaggedObject*> dependents(1);
693  dependents[0] = dependent1;
694 
695  AddCachedResult(result, dependents);
696 }
697 
698 template<class T>
700  T& retResult,
701  const TaggedObject* dependent1
702 )
703 {
704 #ifdef IP_DEBUG_CACHE
705  DBG_START_METH("CachedResults<T>::GetCachedResult1Dep", dbg_verbosity);
706 #endif
707 
708  std::vector<const TaggedObject*> dependents(1);
709  dependents[0] = dependent1;
710 
711  return GetCachedResult(retResult, dependents);
712 }
713 
714 template<class T>
716  const T& result,
717  const TaggedObject* dependent1,
718  const TaggedObject* dependent2
719 )
720 
721 {
722 #ifdef IP_DEBUG_CACHE
723  DBG_START_METH("CachedResults<T>::AddCachedResult2dDep", dbg_verbosity);
724 #endif
725 
726  std::vector<const TaggedObject*> dependents(2);
727  dependents[0] = dependent1;
728  dependents[1] = dependent2;
729 
730  AddCachedResult(result, dependents);
731 }
732 
733 template<class T>
735  T& retResult,
736  const TaggedObject* dependent1,
737  const TaggedObject* dependent2
738 )
739 {
740 #ifdef IP_DEBUG_CACHE
741  DBG_START_METH("CachedResults<T>::GetCachedResult2Dep", dbg_verbosity);
742 #endif
743 
744  std::vector<const TaggedObject*> dependents(2);
745  dependents[0] = dependent1;
746  dependents[1] = dependent2;
747 
748  return GetCachedResult(retResult, dependents);
749 }
750 
751 template<class T>
753  const T& result,
754  const TaggedObject* dependent1,
755  const TaggedObject* dependent2,
756  const TaggedObject* dependent3
757 )
758 {
759 #ifdef IP_DEBUG_CACHE
760  DBG_START_METH("CachedResults<T>::AddCachedResult2dDep", dbg_verbosity);
761 #endif
762 
763  std::vector<const TaggedObject*> dependents(3);
764  dependents[0] = dependent1;
765  dependents[1] = dependent2;
766  dependents[2] = dependent3;
767 
768  AddCachedResult(result, dependents);
769 }
770 
771 template<class T>
773  T& retResult,
774  const TaggedObject* dependent1,
775  const TaggedObject* dependent2,
776  const TaggedObject* dependent3
777 )
778 {
779 #ifdef IP_DEBUG_CACHE
780  DBG_START_METH("CachedResults<T>::GetCachedResult2Dep", dbg_verbosity);
781 #endif
782 
783  std::vector<const TaggedObject*> dependents(3);
784  dependents[0] = dependent1;
785  dependents[1] = dependent2;
786  dependents[2] = dependent3;
787 
788  return GetCachedResult(retResult, dependents);
789 }
790 
791 template<class T>
793  const std::vector<const TaggedObject*>& dependents,
794  const std::vector<Number>& scalar_dependents
795 )
796 {
797  if( !cached_results_ )
798  {
799  return false;
800  }
801 
802  CleanupInvalidatedResults();
803 
804  bool retValue = false;
805  typename std::list<DependentResult<T>*>::const_iterator iter;
806  for( iter = cached_results_->begin(); iter != cached_results_->end(); iter++ )
807  if( (*iter)->DependentsIdentical(dependents, scalar_dependents) )
808  {
809  (*iter)->Invalidate();
810  retValue = true;
811  break;
812  }
813 
814  return retValue;
815 }
816 
817 template<class T>
819 {
820  if( !cached_results_ )
821  {
822  return;
823  }
824 
825  typename std::list<DependentResult<T>*>::const_iterator iter;
826  for( iter = cached_results_->begin(); iter != cached_results_->end(); iter++ )
827  {
828  (*iter)->Invalidate();
829  }
830 
831  CleanupInvalidatedResults();
832 }
833 
834 template<class T>
836  Int max_cache_size
837 )
838 {
839  Clear();
840  max_cache_size_ = max_cache_size;
841 }
842 
843 template<class T>
845 {
846 #ifdef IP_DEBUG_CACHE
847  DBG_START_METH("CachedResults<T>::CleanupInvalidatedResults", dbg_verbosity);
848 #endif
849 
850  if( !cached_results_ )
851  {
852  return;
853  }
854 
855  typename std::list<DependentResult<T>*>::iterator iter;
856  iter = cached_results_->begin();
857  while( iter != cached_results_->end() )
858  {
859  if( (*iter)->IsStale() )
860  {
861  typename std::list<DependentResult<T>*>::iterator iter_to_remove = iter;
862  iter++;
863  DependentResult<T>* result_to_delete = (*iter_to_remove);
864  cached_results_->erase(iter_to_remove);
865  delete result_to_delete;
866  }
867  else
868  {
869  iter++;
870  }
871  }
872 }
873 
874 template<class T>
876 {
877 #ifdef IP_DEBUG_CACHE
878  DBG_START_METH("CachedResults<T>::DebugPrintCachedResults", dbg_verbosity);
879  if (DBG_VERBOSITY() >= 2 )
880  {
881  if (!cached_results_)
882  {
883  DBG_PRINT((2, "Currentlt no cached results:\n"));
884  }
885  else
886  {
887  typename std::list< DependentResult<T>* >::const_iterator iter;
888  DBG_PRINT((2, "Current set of cached results:\n"));
889  for (iter = cached_results_->begin(); iter != cached_results_->end(); iter++)
890  {
891  DBG_PRINT((2, " DependentResult:0x%x\n", (*iter)));
892  }
893  }
894  }
895 #endif
896 
897 }
898 
899 } // namespace Ipopt
900 
901 #endif
#define DBG_ASSERT(test)
Definition: IpDebug.hpp:27
#define DBG_PRINT(__printf_args)
Definition: IpDebug.hpp:39
#define DBG_VERBOSITY()
Definition: IpDebug.hpp:43
#define DBG_START_METH(__func_name, __verbose_level)
Definition: IpDebug.hpp:38
#define DBG_EXEC(__verbosity, __cmd)
Definition: IpDebug.hpp:42
Templated class for Cached Results.
CachedResults()
Default Constructor.
void operator=(const CachedResults &)
Default Assignment Operator.
void Clear(Int max_cache_size)
Invalidate all cached results and changes max_cache_size.
std::list< DependentResult< T > * > * cached_results_
list of currently cached results.
void Clear()
Invalidates all cached results.
void DebugPrintCachedResults() const
Print list of currently cached results.
void AddCachedResult2Dep(const T &result, const TaggedObject *dependent1, const TaggedObject *dependent2)
Method for adding a result to the cache, proving two dependencies as a TaggedObject explicitly.
void AddCachedResult1Dep(const T &result, const TaggedObject *dependent1)
Method for adding a result to the cache, proving one dependency as a TaggedObject explicitly.
CachedResults(Int max_cache_size)
Constructor.
bool GetCachedResult2Dep(T &retResult, const TaggedObject &dependent1, const TaggedObject &dependent2)
bool GetCachedResult1Dep(T &retResult, const TaggedObject *dependent1)
Method for retrieving a cached result, proving one dependency as a TaggedObject explicitly.
bool InvalidateResult(const std::vector< const TaggedObject * > &dependents, const std::vector< Number > &scalar_dependents)
Invalidates the result for given dependencies.
CachedResults(const CachedResults &)
Copy Constructor.
bool GetCachedResult(T &retResult, const std::vector< const TaggedObject * > &dependents) const
Method for retrieving a cached result, providing only a std::vector of TaggedObjects.
bool GetCachedResult(T &retResult, const std::vector< const TaggedObject * > &dependents, const std::vector< Number > &scalar_dependents) const
Generic method for retrieving a cached results, given the dependencies as a std::vector of TaggesObje...
void AddCachedResult3Dep(const T &result, const TaggedObject &dependent1, const TaggedObject &dependent2, const TaggedObject &dependent3)
bool GetCachedResult3Dep(T &retResult, const TaggedObject *dependent1, const TaggedObject *dependent2, const TaggedObject *dependent3)
Method for retrieving a cached result, proving three dependencies as a TaggedObject explicitly.
void CleanupInvalidatedResults() const
internal method for removing stale DependentResults from the list
void AddCachedResult(const T &result, const std::vector< const TaggedObject * > &dependents)
Method for adding a result, providing only a std::vector of TaggedObjects.
bool GetCachedResult2Dep(T &retResult, const TaggedObject *dependent1, const TaggedObject *dependent2)
Method for retrieving a cached result, proving two dependencies as a TaggedObject explicitly.
virtual ~CachedResults()
Destructor.
void AddCachedResult1Dep(const T &result, const TaggedObject &dependent1)
Int max_cache_size_
maximum number of cached results
void AddCachedResult3Dep(const T &result, const TaggedObject *dependent1, const TaggedObject *dependent2, const TaggedObject *dependent3)
Method for adding a result to the cache, proving three dependencies as a TaggedObject explicitly.
bool GetCachedResult1Dep(T &retResult, const TaggedObject &dependent1)
bool GetCachedResult3Dep(T &retResult, const TaggedObject &dependent1, const TaggedObject &dependent2, const TaggedObject &dependent3)
void AddCachedResult2Dep(const T &result, const TaggedObject &dependent1, const TaggedObject &dependent2)
void AddCachedResult(const T &result, const std::vector< const TaggedObject * > &dependents, const std::vector< Number > &scalar_dependents)
Generic method for adding a result to the cache, given a std::vector of TaggesObjects and a std::vect...
Templated class which stores one entry for the CachedResult class.
void DebugPrint() const
Print information about this DependentResults.
const T & GetResult() const
Returns the cached result.
DependentResult()
Default Constructor.
DependentResult(const DependentResult &)
Copy Constructor.
std::vector< TaggedObject::Tag > dependent_tags_
Dependencies in form of TaggedObjects.
const T result_
The value of the dependent results.
bool stale_
Flag indicating, if the cached result is still valid.
std::vector< Number > scalar_dependents_
Dependencies in form a Numbers.
virtual void ReceiveNotification(NotifyType notify_type, const Subject *subject)
Notification Receiver Method.
void Invalidate()
Invalidates the cached result.
bool DependentsIdentical(const std::vector< const TaggedObject * > &dependents, const std::vector< Number > &scalar_dependents) const
This method returns true if the dependencies provided to this function are identical to the ones stor...
bool IsStale() const
Indicates, whether the DependentResult is no longer valid.
void operator=(const DependentResult &)
Default Assignment Operator.
Slight Variation of the Observer Design Pattern.
Definition: IpObserver.hpp:39
NotifyType
Enumeration specifying the type of notification.
Definition: IpObserver.hpp:58
void RequestAttach(NotifyType notify_type, const Subject *subject)
Derived classes should call this method to request an "Attach" to a Subject.
Definition: IpObserver.hpp:254
Slight Variation of the Observer Design Pattern (Subject part).
Definition: IpObserver.hpp:150
TaggedObject class.
This file contains a base class for all exceptions and a set of macros to help with exceptions.
int Int
Type of default integer.
Definition: IpTypes.hpp:19
int Index
Type of all indices of vectors, matrices etc.
Definition: IpTypes.hpp:17