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>
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
72 
73  static const Index dbg_verbosity;
74 #endif
75 
77 
80  int max_cache_size
81  );
82 
84  virtual ~CachedResults();
86 
88 
92  void AddCachedResult(
93  const T& result,
94  const std::vector<const TaggedObject*>& dependents,
95  const std::vector<Number>& scalar_dependents
96  );
97 
102  bool GetCachedResult(
103  T& retResult,
104  const std::vector<const TaggedObject*>& dependents,
105  const std::vector<Number>& scalar_dependents
106  ) const;
107 
109  void AddCachedResult(
110  const T& result,
111  const std::vector<const TaggedObject*>& dependents
112  );
113 
115  bool GetCachedResult(
116  T& retResult,
117  const std::vector<const TaggedObject*>& dependents
118  ) const;
120 
124 
128  void AddCachedResult1Dep(
129  const T& result,
130  const TaggedObject* dependent1
131  );
132 
136  bool GetCachedResult1Dep(
137  T& retResult,
138  const TaggedObject* dependent1
139  );
140 
144  void AddCachedResult2Dep(
145  const T& result,
146  const TaggedObject* dependent1,
147  const TaggedObject* dependent2
148  );
149 
153  bool GetCachedResult2Dep(
154  T& retResult,
155  const TaggedObject* dependent1,
156  const TaggedObject* dependent2
157  );
158 
162  void AddCachedResult3Dep(
163  const T& result,
164  const TaggedObject* dependent1,
165  const TaggedObject* dependent2,
166  const TaggedObject* dependent3
167  );
168 
172  bool GetCachedResult3Dep(
173  T& retResult,
174  const TaggedObject* dependent1,
175  const TaggedObject* dependent2,
176  const TaggedObject* dependent3
177  );
178 
180  bool GetCachedResult1Dep(
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 
241  bool InvalidateResult(
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:
264 
266  CachedResults();
267 
270  const CachedResults&
271  );
272 
274  void operator=(
275  const CachedResults&
276  );
278 
281 
283  mutable std::list<DependentResult<T>*>* cached_results_;
284 
289  void CleanupInvalidatedResults() const;
290 
292  void DebugPrintCachedResults() const;
293 };
294 
300 template<class T>
301 class DependentResult: public Observer
302 {
303 public:
304 
305 #ifdef IP_DEBUG_CACHE
306  static const Index dbg_verbosity;
307 #endif
308 
310 
313  const T& result,
314  const std::vector<const TaggedObject*>& dependents,
315  const std::vector<Number>& scalar_dependents
316  );
317 
321 
323 
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 
372 
374  DependentResult();
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
const T result_
The value of the dependent results.
CachedResults()
Default Constructor.
NotifyType
Enumeration specifying the type of notification.
Definition: IpObserver.hpp:57
const T & GetResult() const
Returns the cached result.
std::vector< Number > scalar_dependents_
Dependencies in form a Numbers.
bool GetCachedResult2Dep(T &retResult, const TaggedObject *dependent1, const TaggedObject *dependent2)
Method for retrieving a cached result, proving two dependencies as a TaggedObject explicitly...
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...
std::vector< TaggedObject::Tag > dependent_tags_
Dependencies in form of TaggedObjects.
#define DBG_START_METH(__func_name, __verbose_level)
Definition: IpDebug.hpp:38
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 operator=(const DependentResult &)
Default Assignment Operator.
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
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...
void operator=(const CachedResults &)
Default Assignment Operator.
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...
#define DBG_EXEC(__verbosity, __cmd)
Definition: IpDebug.hpp:42
Slight Variation of the Observer Design Pattern (Subject part).
Definition: IpObserver.hpp:149
void Invalidate()
Invalidates the cached result.
DependentResult()
Default Constructor.
void AddCachedResult1Dep(const T &result, const TaggedObject &dependent1)
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...
ipindex Index
Type of all indices of vectors, matrices etc.
Definition: IpTypes.hpp:20
void CleanupInvalidatedResults() const
internal method for removing stale DependentResults from the list
TaggedObject class.
This file contains a base class for all exceptions and a set of macros to help with exceptions...
Slight Variation of the Observer Design Pattern.
Definition: IpObserver.hpp:38
virtual void ReceiveNotification(NotifyType notify_type, const Subject *subject)
Notification Receiver Method.
~DependentResult()
Destructor.
virtual ~CachedResults()
Destructor.
bool GetCachedResult2Dep(T &retResult, const TaggedObject &dependent1, const TaggedObject &dependent2)
Cache Priority Enum.
bool GetCachedResult1Dep(T &retResult, const TaggedObject *dependent1)
Method for retrieving a cached result, proving one dependency as a TaggedObject explicitly.
void DebugPrint() const
Print information about this DependentResults.
void Clear()
Invalidates all cached results.
#define DBG_ASSERT(test)
Definition: IpDebug.hpp:27
void AddCachedResult3Dep(const T &result, const TaggedObject &dependent1, const TaggedObject &dependent2, const TaggedObject &dependent3)
std::list< DependentResult< T > * > * cached_results_
list of currently cached results.
#define DBG_PRINT(__printf_args)
Definition: IpDebug.hpp:39
int max_cache_size_
maximum number of cached results
Templated class which stores one entry for the CachedResult class.
bool IsStale() const
Indicates, whether the DependentResult is no longer valid.
bool InvalidateResult(const std::vector< const TaggedObject *> &dependents, const std::vector< Number > &scalar_dependents)
Invalidates the result for given dependencies.
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...
void AddCachedResult1Dep(const T &result, const TaggedObject *dependent1)
Method for adding a result to the cache, proving one dependency as a TaggedObject explicitly...
bool stale_
Flag indicating, if the cached result is still valid.
void DebugPrintCachedResults() const
Print list of currently cached results.
void AddCachedResult2Dep(const T &result, const TaggedObject &dependent1, const TaggedObject &dependent2)
#define DBG_VERBOSITY()
Definition: IpDebug.hpp:43
bool GetCachedResult3Dep(T &retResult, const TaggedObject &dependent1, const TaggedObject &dependent2, const TaggedObject &dependent3)