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(cached_results_->size() <= (size_t)max_cache_size_ + 1);
614  if( cached_results_->size() > (size_t)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  for( typename std::list<DependentResult<T>*>::const_iterator iter = cached_results_->begin(); iter != cached_results_->end(); ++iter )
657  if( (*iter)->DependentsIdentical(dependents, scalar_dependents) )
658  {
659  retResult = (*iter)->GetResult();
660  retValue = true;
661  break;
662  }
663 
664 #ifdef IP_DEBUG_CACHE
665  DBG_EXEC(2, DebugPrintCachedResults());
666 #endif
667 
668  return retValue;
669 }
670 
671 template<class T>
673  T& retResult,
674  const std::vector<const TaggedObject*>& dependents
675 ) const
676 {
677  std::vector<Number> scalar_dependents;
678  return GetCachedResult(retResult, dependents, scalar_dependents);
679 }
680 
681 template<class T>
683  const T& result,
684  const TaggedObject* dependent1
685 )
686 {
687 #ifdef IP_DEBUG_CACHE
688  DBG_START_METH("CachedResults<T>::AddCachedResult1Dep", dbg_verbosity);
689 #endif
690 
691  std::vector<const TaggedObject*> dependents(1);
692  dependents[0] = dependent1;
693 
694  AddCachedResult(result, dependents);
695 }
696 
697 template<class T>
699  T& retResult,
700  const TaggedObject* dependent1
701 )
702 {
703 #ifdef IP_DEBUG_CACHE
704  DBG_START_METH("CachedResults<T>::GetCachedResult1Dep", dbg_verbosity);
705 #endif
706 
707  std::vector<const TaggedObject*> dependents(1);
708  dependents[0] = dependent1;
709 
710  return GetCachedResult(retResult, dependents);
711 }
712 
713 template<class T>
715  const T& result,
716  const TaggedObject* dependent1,
717  const TaggedObject* dependent2
718 )
719 
720 {
721 #ifdef IP_DEBUG_CACHE
722  DBG_START_METH("CachedResults<T>::AddCachedResult2dDep", dbg_verbosity);
723 #endif
724 
725  std::vector<const TaggedObject*> dependents(2);
726  dependents[0] = dependent1;
727  dependents[1] = dependent2;
728 
729  AddCachedResult(result, dependents);
730 }
731 
732 template<class T>
734  T& retResult,
735  const TaggedObject* dependent1,
736  const TaggedObject* dependent2
737 )
738 {
739 #ifdef IP_DEBUG_CACHE
740  DBG_START_METH("CachedResults<T>::GetCachedResult2Dep", dbg_verbosity);
741 #endif
742 
743  std::vector<const TaggedObject*> dependents(2);
744  dependents[0] = dependent1;
745  dependents[1] = dependent2;
746 
747  return GetCachedResult(retResult, dependents);
748 }
749 
750 template<class T>
752  const T& result,
753  const TaggedObject* dependent1,
754  const TaggedObject* dependent2,
755  const TaggedObject* dependent3
756 )
757 {
758 #ifdef IP_DEBUG_CACHE
759  DBG_START_METH("CachedResults<T>::AddCachedResult2dDep", dbg_verbosity);
760 #endif
761 
762  std::vector<const TaggedObject*> dependents(3);
763  dependents[0] = dependent1;
764  dependents[1] = dependent2;
765  dependents[2] = dependent3;
766 
767  AddCachedResult(result, dependents);
768 }
769 
770 template<class T>
772  T& retResult,
773  const TaggedObject* dependent1,
774  const TaggedObject* dependent2,
775  const TaggedObject* dependent3
776 )
777 {
778 #ifdef IP_DEBUG_CACHE
779  DBG_START_METH("CachedResults<T>::GetCachedResult2Dep", dbg_verbosity);
780 #endif
781 
782  std::vector<const TaggedObject*> dependents(3);
783  dependents[0] = dependent1;
784  dependents[1] = dependent2;
785  dependents[2] = dependent3;
786 
787  return GetCachedResult(retResult, dependents);
788 }
789 
790 template<class T>
792  const std::vector<const TaggedObject*>& dependents,
793  const std::vector<Number>& scalar_dependents
794 )
795 {
796  if( !cached_results_ )
797  {
798  return false;
799  }
800 
801  CleanupInvalidatedResults();
802 
803  bool retValue = false;
804  for( typename std::list<DependentResult<T>*>::const_iterator iter = cached_results_->begin(); iter != cached_results_->end(); ++iter )
805  if( (*iter)->DependentsIdentical(dependents, scalar_dependents) )
806  {
807  (*iter)->Invalidate();
808  retValue = true;
809  break;
810  }
811 
812  return retValue;
813 }
814 
815 template<class T>
817 {
818  if( !cached_results_ )
819  {
820  return;
821  }
822 
823  for( typename std::list<DependentResult<T>*>::const_iterator iter = cached_results_->begin(); iter != cached_results_->end(); ++iter )
824  {
825  (*iter)->Invalidate();
826  }
827 
828  CleanupInvalidatedResults();
829 }
830 
831 template<class T>
833  int max_cache_size
834 )
835 {
836  Clear();
837  max_cache_size_ = max_cache_size;
838 }
839 
840 template<class T>
842 {
843 #ifdef IP_DEBUG_CACHE
844  DBG_START_METH("CachedResults<T>::CleanupInvalidatedResults", dbg_verbosity);
845 #endif
846 
847  if( !cached_results_ )
848  {
849  return;
850  }
851 
852  typename std::list<DependentResult<T>*>::iterator iter;
853  iter = cached_results_->begin();
854  while( iter != cached_results_->end() )
855  {
856  if( (*iter)->IsStale() )
857  {
858  typename std::list<DependentResult<T>*>::iterator iter_to_remove = iter++;
859  DependentResult<T>* result_to_delete = (*iter_to_remove);
860  cached_results_->erase(iter_to_remove);
861  delete result_to_delete;
862  }
863  else
864  {
865  ++iter;
866  }
867  }
868 }
869 
870 template<class T>
872 {
873 #ifdef IP_DEBUG_CACHE
874  DBG_START_METH("CachedResults<T>::DebugPrintCachedResults", dbg_verbosity);
875  if (DBG_VERBOSITY() >= 2 )
876  {
877  if (!cached_results_)
878  {
879  DBG_PRINT((2, "Currentlt no cached results:\n"));
880  }
881  else
882  {
883  typename std::list< DependentResult<T>* >::const_iterator iter;
884  DBG_PRINT((2, "Current set of cached results:\n"));
885  for (iter = cached_results_->begin(); iter != cached_results_->end(); ++iter)
886  {
887  DBG_PRINT((2, " DependentResult: %p\n", (void*)*iter));
888  }
889  }
890  }
891 #endif
892 
893 }
894 
895 } // namespace Ipopt
896 
897 #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.
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.
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.
int max_cache_size_
maximum number of cached results
CachedResults(int max_cache_size)
Constructor.
void Clear(int max_cache_size)
Invalidate all cached results and changes max_cache_size.
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)
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.
ipindex Index
Type of all indices of vectors, matrices etc.
Definition: IpTypes.hpp:20