Ipopt  3.12.9
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
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 // $Id: IpCachedResults.hpp 2472 2014-04-05 17:47:20Z stefan $
6 //
7 // Authors: Carl Laird, Andreas Waechter IBM 2004-08-13
8 
9 #ifndef __IPCACHEDRESULTS_HPP__
10 #define __IPCACHEDRESULTS_HPP__
11 
12 #include "IpTaggedObject.hpp"
13 #include "IpObserver.hpp"
14 #include <algorithm>
15 #include <vector>
16 #include <list>
17 
18 namespace Ipopt
19 {
20 
21 #if COIN_IPOPT_CHECKLEVEL > 2
22 # define IP_DEBUG_CACHE
23 #endif
24 #ifdef IP_DEBUG_CACHE
25 # include "IpDebug.hpp"
26 #endif
27 
28  // Forward Declarations
29 
30  template <class T>
32 
33  // AW: I'm taking this out, since this is by far the most used
34  // class. We should keep it as simple as possible.
35  // /** Cache Priority Enum */
36  // enum CachePriority
37  // {
38  // CP_Lowest,
39  // CP_Standard,
40  // CP_Trial,
41  // CP_Iterate
42  // };
43 
69  template <class T>
71  {
72  public:
73 #ifdef IP_DEBUG_CACHE
74 
75  static const Index dbg_verbosity;
76 #endif
77 
84  CachedResults(Int max_cache_size);
85 
87  virtual ~CachedResults();
89 
95  void AddCachedResult(const T& result,
96  const std::vector<const TaggedObject*>& dependents,
97  const std::vector<Number>& scalar_dependents);
98 
103  bool GetCachedResult(T& retResult,
104  const std::vector<const TaggedObject*>& dependents,
105  const std::vector<Number>& scalar_dependents) const;
106 
110  void AddCachedResult(const T& result,
111  const std::vector<const TaggedObject*>& dependents);
112 
116  bool GetCachedResult(T& retResult,
117  const std::vector<const TaggedObject*>& dependents) const;
119 
127  void AddCachedResult1Dep(const T& result,
128  const TaggedObject* dependent1);
129 
133  bool GetCachedResult1Dep(T& retResult, const TaggedObject* dependent1);
134 
138  void AddCachedResult2Dep(const T& result,
139  const TaggedObject* dependent1,
140  const TaggedObject* dependent2);
141 
145  bool GetCachedResult2Dep(T& retResult,
146  const TaggedObject* dependent1,
147  const TaggedObject* dependent2);
148 
152  void AddCachedResult3Dep(const T& result,
153  const TaggedObject* dependent1,
154  const TaggedObject* dependent2,
155  const TaggedObject* dependent3);
156 
160  bool GetCachedResult3Dep(T& retResult,
161  const TaggedObject* dependent1,
162  const TaggedObject* dependent2,
163  const TaggedObject* dependent3);
164 
167  bool GetCachedResult1Dep(T& retResult, const TaggedObject& dependent1)
168  {
169  return GetCachedResult1Dep(retResult, &dependent1);
170  }
171  bool GetCachedResult2Dep(T& retResult,
172  const TaggedObject& dependent1,
173  const TaggedObject& dependent2)
174  {
175  return GetCachedResult2Dep(retResult, &dependent1, &dependent2);
176  }
177  bool GetCachedResult3Dep(T& retResult,
178  const TaggedObject& dependent1,
179  const TaggedObject& dependent2,
180  const TaggedObject& dependent3)
181  {
182  return GetCachedResult3Dep(retResult, &dependent1, &dependent2, &dependent3);
183  }
184  void AddCachedResult1Dep(const T& result,
185  const TaggedObject& dependent1)
186  {
187  AddCachedResult1Dep(result, &dependent1);
188  }
189  void AddCachedResult2Dep(const T& result,
190  const TaggedObject& dependent1,
191  const TaggedObject& dependent2)
192  {
193  AddCachedResult2Dep(result, &dependent1, &dependent2);
194  }
195  void AddCachedResult3Dep(const T& result,
196  const TaggedObject& dependent1,
197  const TaggedObject& dependent2,
198  const TaggedObject& dependent3)
199  {
200  AddCachedResult3Dep(result, &dependent1, &dependent2, &dependent3);
201  }
203 
207  bool InvalidateResult(const std::vector<const TaggedObject*>& dependents,
208  const std::vector<Number>& scalar_dependents);
209 
211  void Clear();
212 
214  void Clear(Int max_cache_size);
215 
216  private:
226  CachedResults();
227 
230 
232  void operator=(const CachedResults&);
234 
237 
239  mutable std::list<DependentResult<T>*>* cached_results_;
240 
245  void CleanupInvalidatedResults() const;
246 
248  void DebugPrintCachedResults() const;
249  };
250 
256  template <class T>
257  class DependentResult : public Observer
258  {
259  public:
260 
261 #ifdef IP_DEBUG_CACHE
262  static const Index dbg_verbosity;
263 #endif
264 
268  DependentResult(const T& result, const std::vector<const TaggedObject*>& dependents,
269  const std::vector<Number>& scalar_dependents);
270 
274 
278  bool IsStale() const;
279 
281  void Invalidate();
282 
284  const T& GetResult() const;
286 
291  bool DependentsIdentical(const std::vector<const TaggedObject*>& dependents,
292  const std::vector<Number>& scalar_dependents) const;
293 
295  void DebugPrint() const;
296 
297  protected:
305  virtual void RecieveNotification(NotifyType notify_type, const Subject* subject);
306 
307  private:
308 
318  DependentResult();
319 
322 
324  void operator=(const DependentResult&);
326 
330  bool stale_;
332  const T result_;
334  std::vector<TaggedObject::Tag> dependent_tags_;
336  std::vector<Number> scalar_dependents_;
337  };
338 
339 #ifdef IP_DEBUG_CACHE
340  template <class T>
342 
343  template <class T>
345 #endif
346 
347  template <class T>
349  const T& result,
350  const std::vector<const TaggedObject*>& dependents,
351  const std::vector<Number>& scalar_dependents)
352  :
353  stale_(false),
354  result_(result),
355  dependent_tags_(dependents.size()),
356  scalar_dependents_(scalar_dependents)
357  {
358 #ifdef IP_DEBUG_CACHE
359  DBG_START_METH("DependentResult<T>::DependentResult()", dbg_verbosity);
360 #endif
361 
362  for (Index i=0; i<(Index)dependents.size(); i++) {
363  if (dependents[i]) {
364  // Call the RequestAttach method of the Observer base class.
365  // This will add this dependent result in the Observer list
366  // for the Subject dependents[i]. As a consequence, the
367  // RecieveNotification method of this DependentResult will be
368  // called with notify_type=NT_Changed, whenever the
369  // TaggedResult dependents[i] is changed (i.e. its HasChanged
370  // method is called).
371  RequestAttach(NT_Changed, dependents[i]);
372  dependent_tags_[i] = dependents[i]->GetTag();
373  }
374  else {
375  dependent_tags_[i] = 0;
376  }
377  }
378  }
379 
380  template <class T>
382  {
383 #ifdef IP_DEBUG_CACHE
384  DBG_START_METH("DependentResult<T>::~DependentResult()", dbg_verbosity);
385  //DBG_ASSERT(stale_ == true);
386 #endif
387  // Nothing to be done here, destructor
388  // of T should sufficiently remove
389  // any memory, etc.
390  }
391 
392  template <class T>
394  {
395  return stale_;
396  }
397 
398  template <class T>
400  {
401  stale_ = true;
402  }
403 
404  template <class T>
406  {
407 #ifdef IP_DEBUG_CACHE
408  DBG_START_METH("DependentResult<T>::RecieveNotification", dbg_verbosity);
409 #endif
410 
411  if (notify_type == NT_Changed || notify_type==NT_BeingDestroyed) {
412  stale_ = true;
413  // technically, I could unregister the notifications here, but they
414  // aren't really hurting anything
415  }
416  }
417 
418  template <class T>
419  bool DependentResult<T>::DependentsIdentical(const std::vector<const TaggedObject*>& dependents,
420  const std::vector<Number>& scalar_dependents) const
421  {
422 #ifdef IP_DEBUG_CACHE
423  DBG_START_METH("DependentResult<T>::DependentsIdentical", dbg_verbosity);
424  DBG_ASSERT(stale_ == false);
425  DBG_ASSERT(dependents.size() == dependent_tags_.size());
426 #endif
427 
428  bool retVal = true;
429 
430  if (dependents.size() != dependent_tags_.size()
431  || scalar_dependents.size() != scalar_dependents_.size()) {
432  retVal = false;
433  }
434  else {
435  for (Index i=0; i<(Index)dependents.size(); i++) {
436  if ( (dependents[i] && dependents[i]->GetTag() != dependent_tags_[i])
437  || (!dependents[i] && dependent_tags_[i] != 0) ) {
438  retVal = false;
439  break;
440  }
441  }
442  if (retVal) {
443  for (Index i=0; i<(Index)scalar_dependents.size(); i++) {
444  if (scalar_dependents[i] != scalar_dependents_[i]) {
445  retVal = false;
446  break;
447  }
448  }
449  }
450  }
451 
452  return retVal;
453  }
454 
455  template <class T>
457  {
458 #ifdef IP_DEBUG_CACHE
459  DBG_START_METH("DependentResult<T>::GetResult()", dbg_verbosity);
460  DBG_ASSERT(stale_ == false);
461 #endif
462 
463  return result_;
464  }
465 
466  template <class T>
468  {
469 #ifdef IP_DEBUG_CACHE
470  DBG_START_METH("DependentResult<T>::DebugPrint", dbg_verbosity);
471 #endif
472 
473  }
474 
475  template <class T>
477  :
478  max_cache_size_(max_cache_size),
479  cached_results_(NULL)
480  {
481 #ifdef IP_DEBUG_CACHE
482  DBG_START_METH("CachedResults<T>::CachedResults", dbg_verbosity);
483 #endif
484 
485  }
486 
487  template <class T>
489  {
490 #ifdef IP_DEBUG_CACHE
491  DBG_START_METH("CachedResults<T>::!CachedResults()", dbg_verbosity);
492 #endif
493 
494  if (cached_results_) {
495  for (typename std::list< DependentResult<T>* >::iterator iter = cached_results_->
496  begin();
497  iter != cached_results_->end();
498  iter++) {
499  delete *iter;
500  }
501  delete cached_results_;
502  }
503  /*
504  while (!cached_results_.empty()) {
505  DependentResult<T>* result = cached_results_.back();
506  cached_results_.pop_back();
507  delete result;
508  }
509  */
510  }
511 
512  template <class T>
513  void CachedResults<T>::AddCachedResult(const T& result,
514  const std::vector<const TaggedObject*>& dependents,
515  const std::vector<Number>& scalar_dependents)
516  {
517 #ifdef IP_DEBUG_CACHE
518  DBG_START_METH("CachedResults<T>::AddCachedResult", dbg_verbosity);
519 #endif
520 
521  CleanupInvalidatedResults();
522 
523  // insert the new one here
524  DependentResult<T>* newResult = new DependentResult<T>(result, dependents, scalar_dependents);
525  if (!cached_results_) {
526  cached_results_ = new std::list<DependentResult<T>*>;
527  }
528  cached_results_->push_front(newResult);
529 
530  // keep the list small enough
531  if (max_cache_size_ >= 0) { // if negative, allow infinite cache
532  // non-negative - limit size of list to max_cache_size
533  DBG_ASSERT((Int)cached_results_->size()<=max_cache_size_+1);
534  if ((Int)cached_results_->size() > max_cache_size_) {
535  delete cached_results_->back();
536  cached_results_->pop_back();
537  }
538  }
539 
540 #ifdef IP_DEBUG_CACHE
541  DBG_EXEC(2, DebugPrintCachedResults());
542 #endif
543 
544  }
545 
546  template <class T>
547  void CachedResults<T>::AddCachedResult(const T& result,
548  const std::vector<const TaggedObject*>& dependents)
549  {
550  std::vector<Number> scalar_dependents;
551  AddCachedResult(result, dependents, scalar_dependents);
552  }
553 
554  template <class T>
555  bool CachedResults<T>::GetCachedResult(T& retResult, const std::vector<const TaggedObject*>& dependents,
556  const std::vector<Number>& scalar_dependents) const
557  {
558 #ifdef IP_DEBUG_CACHE
559  DBG_START_METH("CachedResults<T>::GetCachedResult", dbg_verbosity);
560 #endif
561 
562  if (!cached_results_)
563  return false;
564 
565  CleanupInvalidatedResults();
566 
567  bool retValue = false;
568  typename std::list< DependentResult<T>* >::const_iterator iter;
569  for (iter = cached_results_->begin(); iter != cached_results_->end(); iter++) {
570  if ((*iter)->DependentsIdentical(dependents, scalar_dependents)) {
571  retResult = (*iter)->GetResult();
572  retValue = true;
573  break;
574  }
575  }
576 
577 #ifdef IP_DEBUG_CACHE
578  DBG_EXEC(2, DebugPrintCachedResults());
579 #endif
580 
581  return retValue;
582  }
583 
584  template <class T>
586  T& retResult, const std::vector<const TaggedObject*>& dependents) const
587  {
588  std::vector<Number> scalar_dependents;
589  return GetCachedResult(retResult, dependents, scalar_dependents);
590  }
591 
592  template <class T>
594  const TaggedObject* dependent1)
595  {
596 #ifdef IP_DEBUG_CACHE
597  DBG_START_METH("CachedResults<T>::AddCachedResult1Dep", dbg_verbosity);
598 #endif
599 
600  std::vector<const TaggedObject*> dependents(1);
601  dependents[0] = dependent1;
602 
603  AddCachedResult(result, dependents);
604  }
605 
606  template <class T>
607  bool CachedResults<T>::GetCachedResult1Dep(T& retResult, const TaggedObject* dependent1)
608  {
609 #ifdef IP_DEBUG_CACHE
610  DBG_START_METH("CachedResults<T>::GetCachedResult1Dep", dbg_verbosity);
611 #endif
612 
613  std::vector<const TaggedObject*> dependents(1);
614  dependents[0] = dependent1;
615 
616  return GetCachedResult(retResult, dependents);
617  }
618 
619  template <class T>
620  void CachedResults<T>::AddCachedResult2Dep(const T& result, const TaggedObject* dependent1,
621  const TaggedObject* dependent2)
622 
623  {
624 #ifdef IP_DEBUG_CACHE
625  DBG_START_METH("CachedResults<T>::AddCachedResult2dDep", dbg_verbosity);
626 #endif
627 
628  std::vector<const TaggedObject*> dependents(2);
629  dependents[0] = dependent1;
630  dependents[1] = dependent2;
631 
632  AddCachedResult(result, dependents);
633  }
634 
635  template <class T>
636  bool CachedResults<T>::GetCachedResult2Dep(T& retResult, const TaggedObject* dependent1, const TaggedObject* dependent2)
637  {
638 #ifdef IP_DEBUG_CACHE
639  DBG_START_METH("CachedResults<T>::GetCachedResult2Dep", dbg_verbosity);
640 #endif
641 
642  std::vector<const TaggedObject*> dependents(2);
643  dependents[0] = dependent1;
644  dependents[1] = dependent2;
645 
646  return GetCachedResult(retResult, dependents);
647  }
648 
649  template <class T>
650  void CachedResults<T>::AddCachedResult3Dep(const T& result, const TaggedObject* dependent1,
651  const TaggedObject* dependent2,
652  const TaggedObject* dependent3)
653 
654  {
655 #ifdef IP_DEBUG_CACHE
656  DBG_START_METH("CachedResults<T>::AddCachedResult2dDep", dbg_verbosity);
657 #endif
658 
659  std::vector<const TaggedObject*> dependents(3);
660  dependents[0] = dependent1;
661  dependents[1] = dependent2;
662  dependents[2] = dependent3;
663 
664  AddCachedResult(result, dependents);
665  }
666 
667  template <class T>
668  bool CachedResults<T>::GetCachedResult3Dep(T& retResult, const TaggedObject* dependent1,
669  const TaggedObject* dependent2,
670  const TaggedObject* dependent3)
671  {
672 #ifdef IP_DEBUG_CACHE
673  DBG_START_METH("CachedResults<T>::GetCachedResult2Dep", dbg_verbosity);
674 #endif
675 
676  std::vector<const TaggedObject*> dependents(3);
677  dependents[0] = dependent1;
678  dependents[1] = dependent2;
679  dependents[2] = dependent3;
680 
681  return GetCachedResult(retResult, dependents);
682  }
683 
684  template <class T>
685  bool CachedResults<T>::InvalidateResult(const std::vector<const TaggedObject*>& dependents,
686  const std::vector<Number>& scalar_dependents)
687  {
688  if (!cached_results_)
689  return false;
690 
691  CleanupInvalidatedResults();
692 
693  bool retValue = false;
694  typename std::list< DependentResult<T>* >::const_iterator iter;
695  for (iter = cached_results_->begin(); iter != cached_results_->end();
696  iter++) {
697  if ((*iter)->DependentsIdentical(dependents, scalar_dependents)) {
698  (*iter)->Invalidate();
699  retValue = true;
700  break;
701  }
702  }
703 
704  return retValue;
705  }
706 
707  template <class T>
709  {
710  if (!cached_results_)
711  return;
712 
713  typename std::list< DependentResult<T>* >::const_iterator iter;
714  for (iter = cached_results_->begin(); iter != cached_results_->end();
715  iter++) {
716  (*iter)->Invalidate();
717  }
718 
719  CleanupInvalidatedResults();
720  }
721 
722  template <class T>
723  void CachedResults<T>::Clear(Int max_cache_size)
724  {
725  Clear();
726  max_cache_size_ = max_cache_size;
727  }
728 
729  template <class T>
731  {
732 #ifdef IP_DEBUG_CACHE
733  DBG_START_METH("CachedResults<T>::CleanupInvalidatedResults", dbg_verbosity);
734 #endif
735 
736  if (!cached_results_)
737  return;
738 
739  typename std::list< DependentResult<T>* >::iterator iter;
740  iter = cached_results_->begin();
741  while (iter != cached_results_->end()) {
742  if ((*iter)->IsStale()) {
743  typename std::list< DependentResult<T>* >::iterator
744  iter_to_remove = iter;
745  iter++;
746  DependentResult<T>* result_to_delete = (*iter_to_remove);
747  cached_results_->erase(iter_to_remove);
748  delete result_to_delete;
749  }
750  else {
751  iter++;
752  }
753  }
754  }
755 
756  template <class T>
758  {
759 #ifdef IP_DEBUG_CACHE
760  DBG_START_METH("CachedResults<T>::DebugPrintCachedResults", dbg_verbosity);
761  if (DBG_VERBOSITY()>=2 ) {
762  if (!cached_results_) {
763  DBG_PRINT((2,"Currentlt no cached results:\n"));
764  }
765  else {
766  typename std::list< DependentResult<T>* >::const_iterator iter;
767  DBG_PRINT((2,"Current set of cached results:\n"));
768  for (iter = cached_results_->begin(); iter != cached_results_->end(); iter++) {
769  DBG_PRINT((2," DependentResult:0x%x\n", (*iter)));
770  }
771  }
772  }
773 #endif
774 
775  }
776 
777 } // namespace Ipopt
778 
779 #endif
const T result_
The value of the dependent results.
CachedResults()
Default Constructor.
NotifyType
Enumeration specifying the type of notification.
Definition: IpObserver.hpp:59
void DebugPrint() const
Print information about this DependentResults.
bool InvalidateResult(const std::vector< const TaggedObject * > &dependents, const std::vector< Number > &scalar_dependents)
Invalidates the result for given dependencies.
int Int
Type of default integer.
Definition: IpTypes.hpp:21
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...
std::vector< TaggedObject::Tag > dependent_tags_
Dependencies in form of TaggedObjects.
#define DBG_START_METH(__func_name, __verbose_level)
Definition: IpDebug.hpp:49
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...
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 operator=(const DependentResult &)
Overloaded Equals Operator.
void RequestAttach(NotifyType notify_type, const Subject *subject)
Derived classes should call this method to request an &quot;Attach&quot; to a Subject.
Definition: IpObserver.hpp:219
void operator=(const CachedResults &)
Overloaded Equals Operator.
#define DBG_EXEC(__verbosity, __cmd)
Definition: IpDebug.hpp:53
Slight Variation of the Observer Design Pattern (Subject part).
Definition: IpObserver.hpp:129
void Invalidate()
Invalidates the cached result.
DependentResult()
Default Constructor.
Int max_cache_size_
maximum number of cached results
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...
TaggedObject class.
Slight Variation of the Observer Design Pattern.
Definition: IpObserver.hpp:39
~DependentResult()
Destructor.
virtual ~CachedResults()
Destructor.
bool GetCachedResult2Dep(T &retResult, const TaggedObject &dependent1, const TaggedObject &dependent2)
void CleanupInvalidatedResults() const
internal method for removing stale DependentResults from the list.
bool IsStale() const
This returns true, if the DependentResult is no longer valid.
Cache Priority Enum.
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 GetCachedResult1Dep(T &retResult, const TaggedObject &dependent1)
bool GetCachedResult1Dep(T &retResult, const TaggedObject *dependent1)
Method for retrieving a cached result, proving one dependency as a TaggedObject explicitly.
virtual void RecieveNotification(NotifyType notify_type, const Subject *subject)
This method is overloading the pure virtual method from the Observer base class.
void Clear()
Invalidates all cached results.
int Index
Type of all indices of vectors, matrices etc.
Definition: IpTypes.hpp:19
#define DBG_ASSERT(test)
Definition: IpDebug.hpp:38
const T & GetResult() const
Returns the cached result.
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:50
Templated class which stores one entry for the CachedResult class.
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...
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...
bool stale_
Flag indicating, if the cached result is still valid.
void AddCachedResult2Dep(const T &result, const TaggedObject &dependent1, const TaggedObject &dependent2)
void DebugPrintCachedResults() const
Print list of currently cached results.
#define DBG_VERBOSITY()
Definition: IpDebug.hpp:54
bool GetCachedResult3Dep(T &retResult, const TaggedObject &dependent1, const TaggedObject &dependent2, const TaggedObject &dependent3)