1 // @HEADER 2 // ************************************************************************ 3 // 4 // Rapid Optimization Library (ROL) Package 5 // Copyright (2014) Sandia Corporation 6 // 7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 8 // license for use of this work by or on behalf of the U.S. Government. 9 // 10 // Redistribution and use in source and binary forms, with or without 11 // modification, are permitted provided that the following conditions are 12 // met: 13 // 14 // 1. Redistributions of source code must retain the above copyright 15 // notice, this list of conditions and the following disclaimer. 16 // 17 // 2. Redistributions in binary form must reproduce the above copyright 18 // notice, this list of conditions and the following disclaimer in the 19 // documentation and/or other materials provided with the distribution. 20 // 21 // 3. Neither the name of the Corporation nor the names of the 22 // contributors may be used to endorse or promote products derived from 23 // this software without specific prior written permission. 24 // 25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 // 37 // Questions? Contact lead developers: 38 // Drew Kouri (dpkouri@sandia.gov) and 39 // Denis Ridzal (dridzal@sandia.gov) 40 // 41 // ************************************************************************ 42 // @HEADER 43 44 #pragma once 45 #ifndef ROL_VECTORWORKSPACE_HPP 46 #define ROL_VECTORWORKSPACE_HPP 47 48 #include "ROL_Vector.hpp" 49 #include <iostream> 50 #include <map> 51 #include <utility> 52 53 /** @ingroup la_group 54 \class ROL::VectorWorkspace 55 \brief Provides a "smart" cloning manager to be used a member variable in 56 a class and called in the member function of the same class. 57 58 VectorWorkspace::clone( const Vector& x ) and 59 VectorWorkspace::clone( const Ptr<Vector>& x ) 60 61 Will allocate new memory of a clone of x *if needed* and return 62 a pointer to the clone. A new clone is considered to be needed 63 only if these is not a previously allocated compatible vector 64 stored in the VectorWorkspace. 65 66 Compatibility is determined by derived type (typeid::hash_code) 67 and vector dimension. Together these form a VectorKey. 68 When cloning a vector inside a member function, VectorWorkspace 69 will identify it's VectorKey type. If such a type exists in the 70 database, with will then refer to the associated VectorStack that 71 is specific to the VectorKey type. 72 73 The VectorStack will be searched for the first available dynamically 74 allocated vector which has no external references to it and return 75 a pointer to it. If no such vector exists, a new one will be 76 cloned and added to the stack. When the local pointers to the 77 VectorStack elements go out of scope at the end of the member 78 function, the reference counts are decremented and the vectors 79 become available for use again. 80 81 NOTE: Stored clones will have a reference count of 2 when there 82 are no external pointers to the same object. 83 84 It should also be possible use a single VectorWorkspace in 85 multiple levels of nested objects. 86 87 The concept could probably also generalize to the MPI setting 88 where node locality is an additional distinguishing qualifier 89 for cloning. 90 91 */ 92 93 namespace ROL { 94 95 namespace details { 96 97 using namespace std; 98 99 100 template<typename Real> 101 class VectorWorkspace { 102 103 using V = ROL::Vector<Real>; 104 using size_type = typename vector<Real>::size_type; 105 106 private: 107 108 struct VectorKey { 109 friend class VectorWorkspace<Real>; 110 size_t hash_code; 111 int dimension; 112 VectorKeyROL::details::VectorWorkspace::VectorKey113 VectorKey( const V& x ) : 114 hash_code(typeid(x).hash_code()), 115 dimension( x.dimension() ) {} 116 VectorKeyROL::details::VectorWorkspace::VectorKey117 VectorKey( const Ptr<V>& x ) : 118 VectorKey( *x ) {} 119 to_stringROL::details::VectorWorkspace::VectorKey120 static string to_string( const VectorKey& key ) { 121 stringstream ss; 122 ss << "VectorKey(" << hex << key.hash_code << "," 123 << dec << key.dimension << ")"; 124 return ss.str(); 125 } 126 operator <ROL::details::VectorWorkspace::VectorKey127 bool operator < ( const VectorKey& x ) const { 128 return ( hash_code < x.hash_code ) && ( dimension < x.dimension ); 129 } 130 operator ==ROL::details::VectorWorkspace::VectorKey131 bool operator == ( const VectorKey& x ) const { 132 return ( hash_code == x.hash_code ) && ( dimension == x.dimension ); 133 } 134 135 // bool operator != ( const VectorKey& x ) const { 136 // return ( hash_code != x.hash_code ) || ( dimension != x.dimension ); 137 // } 138 139 }; // class VectorKey 140 141 struct VectorStack { 142 143 friend class VectorWorkspace<Real>; 144 vector<Ptr<V>> vectors_; 145 VectorKey key_; 146 VectorStackROL::details::VectorWorkspace::VectorStack147 VectorStack( const V& x ) : vectors_( 1, x.clone() ), 148 key_(VectorKey(x)) {} 149 getKeyROL::details::VectorWorkspace::VectorStack150 const VectorKey& getKey() const { return key_; } 151 sizeROL::details::VectorWorkspace::VectorStack152 size_type size() const { return vectors_.size(); } 153 number_assignedROL::details::VectorWorkspace::VectorStack154 size_type number_assigned() const { 155 size_type count = 0; 156 for( auto v : vectors_ ) count += ( getCount(v) > 3 ); 157 return count; 158 } 159 160 /** If no next element exists, clone it, increment the index, and 161 return a the clone by pointer 162 */ cloneROL::details::VectorWorkspace::VectorStack163 Ptr<V> clone( const V& x ) { 164 VectorKey x_key(x); 165 166 ROL_TEST_FOR_EXCEPTION( key_.hash_code != x_key.hash_code, logic_error, 167 "VectorWorkspace::VectorStack tried to clone a vector of type " << 168 hex << key_.hash_code << ", but it can only clone vectors of type " << 169 hex << x_key.hash_code ); 170 171 ROL_TEST_FOR_EXCEPTION( key_.dimension != x_key.dimension, logic_error, 172 "VectorWorkspace::VectorStack tried to clone a vector of dimension " << 173 hex << key_.dimension << ", but it can only clone vectors of dimension " << 174 hex << x_key.dimension ); 175 176 for( auto e : vectors_ ) { // Return first unreferenced vector 177 if( getCount(e) <= 2 ) { // Storing pointers in vector increments count 178 return e; 179 } 180 } 181 // If no unreferenced vectors exist, add a new one 182 auto v = x.clone(); 183 vectors_.push_back( v ); 184 return v; 185 } 186 187 // For testing purposes getRefCountsROL::details::VectorWorkspace::VectorStack188 vector<size_type> getRefCounts( void ) const { 189 vector<size_type> counts; 190 for( auto e: vectors_ ) counts.push_back( getCount(e) ); 191 return counts; 192 } 193 194 }; // VectorStack 195 196 map<VectorKey,Ptr<VectorStack>> workspace_; 197 198 public: 199 clone(const V & x)200 Ptr<V> clone( const V& x ) { 201 202 VectorKey key(x); 203 size_type key_count{0}; 204 Ptr<VectorStack> vstack{nullPtr}; 205 206 for( auto e : workspace_ ) key_count += (key == e.first); 207 208 if( key_count == 0 ) { // New key 209 vstack = makePtr<VectorStack>(x); 210 workspace_.insert( make_pair(key,vstack) ); 211 } 212 else vstack = workspace_[key]; 213 214 return vstack->clone(x); 215 } 216 clone(const Ptr<const V> & x)217 Ptr<V> clone( const Ptr<const V>& x ) { return clone(*x); } 218 219 // Deep copy copy(const V & x)220 Ptr<V> copy( const V& x ) { 221 auto xc = clone(x); 222 xc->set(x); 223 return xc; 224 } 225 copy(const Ptr<const V> & x)226 Ptr<V> copy( const Ptr<const V>& x ) { return copy(*x); } 227 status(ostream & os) const228 void status( ostream& os ) const { 229 os << "\n\n" << string(80,'-') << std::endl; 230 os << "VectorWorkspace contains the following VectorStack(hash_code,dim) entries:\n\n"; 231 for( auto entry : workspace_ ) { 232 os << " VectorStack(" << hex << entry.first.hash_code << "," 233 << dec << entry.first.dimension << ")"; 234 os << "\n Reference Counts per element" << std::endl; 235 for( auto e : entry.second->vectors_ ) { 236 os << " " << getCount( e ) << std::endl; 237 } 238 } 239 os << string(80,'-') << std::endl; 240 } 241 242 243 }; // VectorWorkspace 244 245 } // namespace details 246 247 using details::VectorWorkspace; 248 249 } // namespace ROL 250 251 252 #endif 253