open source driving agent
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

779 lines
24 KiB

// Copyright (C) 2004, 2011 International Business Machines and others.
// All Rights Reserved.
// This code is published under the Eclipse Public License.
//
// $Id: IpCachedResults.hpp 2472 2014-04-05 17:47:20Z stefan $
//
// Authors: Carl Laird, Andreas Waechter IBM 2004-08-13
#ifndef __IPCACHEDRESULTS_HPP__
#define __IPCACHEDRESULTS_HPP__
#include "IpTaggedObject.hpp"
#include "IpObserver.hpp"
#include <algorithm>
#include <vector>
#include <list>
namespace Ipopt
{
#if COIN_IPOPT_CHECKLEVEL > 2
# define IP_DEBUG_CACHE
#endif
#ifdef IP_DEBUG_CACHE
# include "IpDebug.hpp"
#endif
// Forward Declarations
template <class T>
class DependentResult;
// AW: I'm taking this out, since this is by far the most used
// class. We should keep it as simple as possible.
// /** Cache Priority Enum */
// enum CachePriority
// {
// CP_Lowest,
// CP_Standard,
// CP_Trial,
// CP_Iterate
// };
/** Templated class for Cached Results. This class stores up to a
* given number of "results", entities that are stored here
* together with identifiers, that can be used to later retrieve the
* information again.
*
* Typically, T is a SmartPtr for some calculated quantity that
* should be stored (such as a Vector). The identifiers (or
* dependencies) are a (possibly varying) number of Tags from
* TaggedObjects, and a number of Numbers. Results are added to
* the cache using the AddCachedResults methods, and the can be
* retrieved with the GetCachedResults methods. The second set of
* methods checks whether a result has been cached for the given
* identifiers. If a corresponding result is found, a copy of it
* is returned and the method evaluates to true, otherwise it
* evaluates to false.
*
* Note that cached results can become "stale", namely when a
* TaggedObject that is used to identify this CachedResult is
* changed. When this happens, the cached result can never be
* asked for again, so that there is no point in storing it any
* longer. For this purpose, a cached result, which is stored as a
* DependentResult, inherits off an Observer. This Observer
* retrieves notification whenever a TaggedObject dependency has
* changed. Stale results are later removed from the cache.
*/
template <class T>
class CachedResults
{
public:
#ifdef IP_DEBUG_CACHE
/** (Only if compiled in DEBUG mode): debug verbosity level */
static const Index dbg_verbosity;
#endif
/** @name Constructors and Destructors. */
//@{
/** Constructor, where max_cache_size is the maximal number of
* results that should be cached. If max_cache_size is negative,
* we allow an infinite amount of cache.
*/
CachedResults(Int max_cache_size);
/** Destructor */
virtual ~CachedResults();
//@}
/** @name Generic methods for adding and retrieving cached results. */
//@{
/** Generic method for adding a result to the cache, given a
* std::vector of TaggesObjects and a std::vector of Numbers.
*/
void AddCachedResult(const T& result,
const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents);
/** Generic method for retrieving a cached results, given the
* dependencies as a std::vector of TaggesObjects and a
* std::vector of Numbers.
*/
bool GetCachedResult(T& retResult,
const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents) const;
/** Method for adding a result, providing only a std::vector of
* TaggedObjects.
*/
void AddCachedResult(const T& result,
const std::vector<const TaggedObject*>& dependents);
/** Method for retrieving a cached result, providing only a
* std::vector of TaggedObjects.
*/
bool GetCachedResult(T& retResult,
const std::vector<const TaggedObject*>& dependents) const;
//@}
/** @name Pointer-based methods for adding and retrieving cached
* results, providing dependencies explicitly.
*/
//@{
/** Method for adding a result to the cache, proving one
* dependency as a TaggedObject explicitly.
*/
void AddCachedResult1Dep(const T& result,
const TaggedObject* dependent1);
/** Method for retrieving a cached result, proving one dependency
* as a TaggedObject explicitly.
*/
bool GetCachedResult1Dep(T& retResult, const TaggedObject* dependent1);
/** Method for adding a result to the cache, proving two
* dependencies as a TaggedObject explicitly.
*/
void AddCachedResult2Dep(const T& result,
const TaggedObject* dependent1,
const TaggedObject* dependent2);
/** Method for retrieving a cached result, proving two
* dependencies as a TaggedObject explicitly.
*/
bool GetCachedResult2Dep(T& retResult,
const TaggedObject* dependent1,
const TaggedObject* dependent2);
/** Method for adding a result to the cache, proving three
* dependencies as a TaggedObject explicitly.
*/
void AddCachedResult3Dep(const T& result,
const TaggedObject* dependent1,
const TaggedObject* dependent2,
const TaggedObject* dependent3);
/** Method for retrieving a cached result, proving three
* dependencies as a TaggedObject explicitly.
*/
bool GetCachedResult3Dep(T& retResult,
const TaggedObject* dependent1,
const TaggedObject* dependent2,
const TaggedObject* dependent3);
/** @name Pointer-free version of the Add and Get methods */
//@{
bool GetCachedResult1Dep(T& retResult, const TaggedObject& dependent1)
{
return GetCachedResult1Dep(retResult, &dependent1);
}
bool GetCachedResult2Dep(T& retResult,
const TaggedObject& dependent1,
const TaggedObject& dependent2)
{
return GetCachedResult2Dep(retResult, &dependent1, &dependent2);
}
bool GetCachedResult3Dep(T& retResult,
const TaggedObject& dependent1,
const TaggedObject& dependent2,
const TaggedObject& dependent3)
{
return GetCachedResult3Dep(retResult, &dependent1, &dependent2, &dependent3);
}
void AddCachedResult1Dep(const T& result,
const TaggedObject& dependent1)
{
AddCachedResult1Dep(result, &dependent1);
}
void AddCachedResult2Dep(const T& result,
const TaggedObject& dependent1,
const TaggedObject& dependent2)
{
AddCachedResult2Dep(result, &dependent1, &dependent2);
}
void AddCachedResult3Dep(const T& result,
const TaggedObject& dependent1,
const TaggedObject& dependent2,
const TaggedObject& dependent3)
{
AddCachedResult3Dep(result, &dependent1, &dependent2, &dependent3);
}
//@}
/** Invalidates the result for given dependencies. Sets the stale
* flag for the corresponding cached result to true if it is
* found. Returns true, if the result was found. */
bool InvalidateResult(const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents);
/** Invalidates all cached results */
void Clear();
/** Invalidate all cached results and changes max_cache_size */
void Clear(Int max_cache_size);
private:
/**@name Default Compiler Generated Methods
* (Hidden to avoid implicit creation/calling).
* These methods are not implemented and
* we do not want the compiler to implement
* them for us, so we declare them private
* and do not define them. This ensures that
* they will not be implicitly created/called. */
//@{
/** Default Constructor */
CachedResults();
/** Copy Constructor */
CachedResults(const CachedResults&);
/** Overloaded Equals Operator */
void operator=(const CachedResults&);
//@}
/** maximum number of cached results */
Int max_cache_size_;
/** list of currently cached results. */
mutable std::list<DependentResult<T>*>* cached_results_;
/** internal method for removing stale DependentResults from the
* list. It is called at the beginning of every
* GetDependentResult method.
*/
void CleanupInvalidatedResults() const;
/** Print list of currently cached results */
void DebugPrintCachedResults() const;
};
/** Templated class which stores one entry for the CachedResult
* class. It stores the result (of type T), together with its
* dependencies (vector of TaggedObjects and vector of Numbers).
* It also stores a priority.
*/
template <class T>
class DependentResult : public Observer
{
public:
#ifdef IP_DEBUG_CACHE
static const Index dbg_verbosity;
#endif
/** @name Constructor, Destructors */
//@{
/** Constructor, given all information about the result. */
DependentResult(const T& result, const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents);
/** Destructor. */
~DependentResult();
//@}
/** @name Accessor method. */
//@{
/** This returns true, if the DependentResult is no longer valid. */
bool IsStale() const;
/** Invalidates the cached result. */
void Invalidate();
/** Returns the cached result. */
const T& GetResult() const;
//@}
/** This method returns true if the dependencies provided to this
* function are identical to the ones stored with the
* DependentResult.
*/
bool DependentsIdentical(const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents) const;
/** Print information about this DependentResults. */
void DebugPrint() const;
protected:
/** This method is overloading the pure virtual method from the
* Observer base class. This method is called when a Subject
* registered for this Observer sends a notification. In this
* particular case, if this method is called with
* notify_type==NT_Changed or NT_BeingDeleted, then this results
* is marked as stale.
*/
virtual void RecieveNotification(NotifyType notify_type, const Subject* subject);
private:
/**@name Default Compiler Generated Methods
* (Hidden to avoid implicit creation/calling).
* These methods are not implemented and
* we do not want the compiler to implement
* them for us, so we declare them private
* and do not define them. This ensures that
* they will not be implicitly created/called. */
//@{
/** Default Constructor */
DependentResult();
/** Copy Constructor */
DependentResult(const DependentResult&);
/** Overloaded Equals Operator */
void operator=(const DependentResult&);
//@}
/** Flag indicating, if the cached result is still valid. A
result becomes invalid, if the RecieveNotification method is
called with NT_Changed */
bool stale_;
/** The value of the dependent results */
const T result_;
/** Dependencies in form of TaggedObjects */
std::vector<TaggedObject::Tag> dependent_tags_;
/** Dependencies in form a Numbers */
std::vector<Number> scalar_dependents_;
};
#ifdef IP_DEBUG_CACHE
template <class T>
const Index CachedResults<T>::dbg_verbosity = 0;
template <class T>
const Index DependentResult<T>::dbg_verbosity = 0;
#endif
template <class T>
DependentResult<T>::DependentResult(
const T& result,
const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents)
:
stale_(false),
result_(result),
dependent_tags_(dependents.size()),
scalar_dependents_(scalar_dependents)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("DependentResult<T>::DependentResult()", dbg_verbosity);
#endif
for (Index i=0; i<(Index)dependents.size(); i++) {
if (dependents[i]) {
// Call the RequestAttach method of the Observer base class.
// This will add this dependent result in the Observer list
// for the Subject dependents[i]. As a consequence, the
// RecieveNotification method of this DependentResult will be
// called with notify_type=NT_Changed, whenever the
// TaggedResult dependents[i] is changed (i.e. its HasChanged
// method is called).
RequestAttach(NT_Changed, dependents[i]);
dependent_tags_[i] = dependents[i]->GetTag();
}
else {
dependent_tags_[i] = 0;
}
}
}
template <class T>
DependentResult<T>::~DependentResult()
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("DependentResult<T>::~DependentResult()", dbg_verbosity);
//DBG_ASSERT(stale_ == true);
#endif
// Nothing to be done here, destructor
// of T should sufficiently remove
// any memory, etc.
}
template <class T>
bool DependentResult<T>::IsStale() const
{
return stale_;
}
template <class T>
void DependentResult<T>::Invalidate()
{
stale_ = true;
}
template <class T>
void DependentResult<T>::RecieveNotification(NotifyType notify_type, const Subject* subject)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("DependentResult<T>::RecieveNotification", dbg_verbosity);
#endif
if (notify_type == NT_Changed || notify_type==NT_BeingDestroyed) {
stale_ = true;
// technically, I could unregister the notifications here, but they
// aren't really hurting anything
}
}
template <class T>
bool DependentResult<T>::DependentsIdentical(const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents) const
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("DependentResult<T>::DependentsIdentical", dbg_verbosity);
DBG_ASSERT(stale_ == false);
DBG_ASSERT(dependents.size() == dependent_tags_.size());
#endif
bool retVal = true;
if (dependents.size() != dependent_tags_.size()
|| scalar_dependents.size() != scalar_dependents_.size()) {
retVal = false;
}
else {
for (Index i=0; i<(Index)dependents.size(); i++) {
if ( (dependents[i] && dependents[i]->GetTag() != dependent_tags_[i])
|| (!dependents[i] && dependent_tags_[i] != 0) ) {
retVal = false;
break;
}
}
if (retVal) {
for (Index i=0; i<(Index)scalar_dependents.size(); i++) {
if (scalar_dependents[i] != scalar_dependents_[i]) {
retVal = false;
break;
}
}
}
}
return retVal;
}
template <class T>
const T& DependentResult<T>::GetResult() const
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("DependentResult<T>::GetResult()", dbg_verbosity);
DBG_ASSERT(stale_ == false);
#endif
return result_;
}
template <class T>
void DependentResult<T>::DebugPrint() const
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("DependentResult<T>::DebugPrint", dbg_verbosity);
#endif
}
template <class T>
CachedResults<T>::CachedResults(Int max_cache_size)
:
max_cache_size_(max_cache_size),
cached_results_(NULL)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::CachedResults", dbg_verbosity);
#endif
}
template <class T>
CachedResults<T>::~CachedResults()
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::!CachedResults()", dbg_verbosity);
#endif
if (cached_results_) {
for (typename std::list< DependentResult<T>* >::iterator iter = cached_results_->
begin();
iter != cached_results_->end();
iter++) {
delete *iter;
}
delete cached_results_;
}
/*
while (!cached_results_.empty()) {
DependentResult<T>* result = cached_results_.back();
cached_results_.pop_back();
delete result;
}
*/
}
template <class T>
void CachedResults<T>::AddCachedResult(const T& result,
const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::AddCachedResult", dbg_verbosity);
#endif
CleanupInvalidatedResults();
// insert the new one here
DependentResult<T>* newResult = new DependentResult<T>(result, dependents, scalar_dependents);
if (!cached_results_) {
cached_results_ = new std::list<DependentResult<T>*>;
}
cached_results_->push_front(newResult);
// keep the list small enough
if (max_cache_size_ >= 0) { // if negative, allow infinite cache
// non-negative - limit size of list to max_cache_size
DBG_ASSERT((Int)cached_results_->size()<=max_cache_size_+1);
if ((Int)cached_results_->size() > max_cache_size_) {
delete cached_results_->back();
cached_results_->pop_back();
}
}
#ifdef IP_DEBUG_CACHE
DBG_EXEC(2, DebugPrintCachedResults());
#endif
}
template <class T>
void CachedResults<T>::AddCachedResult(const T& result,
const std::vector<const TaggedObject*>& dependents)
{
std::vector<Number> scalar_dependents;
AddCachedResult(result, dependents, scalar_dependents);
}
template <class T>
bool CachedResults<T>::GetCachedResult(T& retResult, const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents) const
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::GetCachedResult", dbg_verbosity);
#endif
if (!cached_results_)
return false;
CleanupInvalidatedResults();
bool retValue = false;
typename std::list< DependentResult<T>* >::const_iterator iter;
for (iter = cached_results_->begin(); iter != cached_results_->end(); iter++) {
if ((*iter)->DependentsIdentical(dependents, scalar_dependents)) {
retResult = (*iter)->GetResult();
retValue = true;
break;
}
}
#ifdef IP_DEBUG_CACHE
DBG_EXEC(2, DebugPrintCachedResults());
#endif
return retValue;
}
template <class T>
bool CachedResults<T>::GetCachedResult(
T& retResult, const std::vector<const TaggedObject*>& dependents) const
{
std::vector<Number> scalar_dependents;
return GetCachedResult(retResult, dependents, scalar_dependents);
}
template <class T>
void CachedResults<T>::AddCachedResult1Dep(const T& result,
const TaggedObject* dependent1)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::AddCachedResult1Dep", dbg_verbosity);
#endif
std::vector<const TaggedObject*> dependents(1);
dependents[0] = dependent1;
AddCachedResult(result, dependents);
}
template <class T>
bool CachedResults<T>::GetCachedResult1Dep(T& retResult, const TaggedObject* dependent1)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::GetCachedResult1Dep", dbg_verbosity);
#endif
std::vector<const TaggedObject*> dependents(1);
dependents[0] = dependent1;
return GetCachedResult(retResult, dependents);
}
template <class T>
void CachedResults<T>::AddCachedResult2Dep(const T& result, const TaggedObject* dependent1,
const TaggedObject* dependent2)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::AddCachedResult2dDep", dbg_verbosity);
#endif
std::vector<const TaggedObject*> dependents(2);
dependents[0] = dependent1;
dependents[1] = dependent2;
AddCachedResult(result, dependents);
}
template <class T>
bool CachedResults<T>::GetCachedResult2Dep(T& retResult, const TaggedObject* dependent1, const TaggedObject* dependent2)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::GetCachedResult2Dep", dbg_verbosity);
#endif
std::vector<const TaggedObject*> dependents(2);
dependents[0] = dependent1;
dependents[1] = dependent2;
return GetCachedResult(retResult, dependents);
}
template <class T>
void CachedResults<T>::AddCachedResult3Dep(const T& result, const TaggedObject* dependent1,
const TaggedObject* dependent2,
const TaggedObject* dependent3)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::AddCachedResult2dDep", dbg_verbosity);
#endif
std::vector<const TaggedObject*> dependents(3);
dependents[0] = dependent1;
dependents[1] = dependent2;
dependents[2] = dependent3;
AddCachedResult(result, dependents);
}
template <class T>
bool CachedResults<T>::GetCachedResult3Dep(T& retResult, const TaggedObject* dependent1,
const TaggedObject* dependent2,
const TaggedObject* dependent3)
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::GetCachedResult2Dep", dbg_verbosity);
#endif
std::vector<const TaggedObject*> dependents(3);
dependents[0] = dependent1;
dependents[1] = dependent2;
dependents[2] = dependent3;
return GetCachedResult(retResult, dependents);
}
template <class T>
bool CachedResults<T>::InvalidateResult(const std::vector<const TaggedObject*>& dependents,
const std::vector<Number>& scalar_dependents)
{
if (!cached_results_)
return false;
CleanupInvalidatedResults();
bool retValue = false;
typename std::list< DependentResult<T>* >::const_iterator iter;
for (iter = cached_results_->begin(); iter != cached_results_->end();
iter++) {
if ((*iter)->DependentsIdentical(dependents, scalar_dependents)) {
(*iter)->Invalidate();
retValue = true;
break;
}
}
return retValue;
}
template <class T>
void CachedResults<T>::Clear()
{
if (!cached_results_)
return;
typename std::list< DependentResult<T>* >::const_iterator iter;
for (iter = cached_results_->begin(); iter != cached_results_->end();
iter++) {
(*iter)->Invalidate();
}
CleanupInvalidatedResults();
}
template <class T>
void CachedResults<T>::Clear(Int max_cache_size)
{
Clear();
max_cache_size_ = max_cache_size;
}
template <class T>
void CachedResults<T>::CleanupInvalidatedResults() const
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::CleanupInvalidatedResults", dbg_verbosity);
#endif
if (!cached_results_)
return;
typename std::list< DependentResult<T>* >::iterator iter;
iter = cached_results_->begin();
while (iter != cached_results_->end()) {
if ((*iter)->IsStale()) {
typename std::list< DependentResult<T>* >::iterator
iter_to_remove = iter;
iter++;
DependentResult<T>* result_to_delete = (*iter_to_remove);
cached_results_->erase(iter_to_remove);
delete result_to_delete;
}
else {
iter++;
}
}
}
template <class T>
void CachedResults<T>::DebugPrintCachedResults() const
{
#ifdef IP_DEBUG_CACHE
DBG_START_METH("CachedResults<T>::DebugPrintCachedResults", dbg_verbosity);
if (DBG_VERBOSITY()>=2 ) {
if (!cached_results_) {
DBG_PRINT((2,"Currentlt no cached results:\n"));
}
else {
typename std::list< DependentResult<T>* >::const_iterator iter;
DBG_PRINT((2,"Current set of cached results:\n"));
for (iter = cached_results_->begin(); iter != cached_results_->end(); iter++) {
DBG_PRINT((2," DependentResult:0x%x\n", (*iter)));
}
}
}
#endif
}
} // namespace Ipopt
#endif