CppAD: A C++ Algorithmic Differentiation Package
20130102
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_TAPE_LINK_INCLUDED 00003 # define CPPAD_TAPE_LINK_INCLUDED 00004 00005 /* -------------------------------------------------------------------------- 00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-12 Bradley M. Bell 00007 00008 CppAD is distributed under multiple licenses. This distribution is under 00009 the terms of the 00010 Eclipse Public License Version 1.0. 00011 00012 A copy of this license is included in the COPYING file of this distribution. 00013 Please visit http://www.coin-or.org/CppAD/ for information on other licenses. 00014 -------------------------------------------------------------------------- */ 00015 00016 # include <cppad/local/define.hpp> 00017 # include <cppad/thread_alloc.hpp> 00018 # include <cppad/local/cppad_assert.hpp> 00019 00020 // needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL 00021 # include <cppad/thread_alloc.hpp> 00022 00023 CPPAD_BEGIN_NAMESPACE 00024 /*! 00025 \defgroup tape_link_hpp tape_link.hpp 00026 \{ 00027 \file tape_link.hpp 00028 Routines that Link AD<Base> and ADTape<Base> Objects \ref tape_link_hpp. 00029 00030 The routines that connect the AD<Base> class to the corresponding tapes 00031 (one for each thread). 00032 */ 00033 00034 /*! 00035 Handle to the tape identifier for this AD<Base> class and the specific thread. 00036 00037 \tparam Base 00038 is the base type for this AD<Base> class. 00039 00040 \param thread 00041 is the thread number. The following condition must hold 00042 \code 00043 (! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num() 00044 \endcode 00045 00046 \return 00047 is a handle to the tape identifier for this thread 00048 and AD<Base> class. 00049 */ 00050 template <class Base> 00051 inline tape_id_t** AD<Base>::tape_id_handle(size_t thread) 00052 { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; 00053 static tape_id_t* tape_id_table[CPPAD_MAX_NUM_THREADS]; 00054 CPPAD_ASSERT_UNKNOWN( 00055 (! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num() 00056 ); 00057 00058 return tape_id_table + thread; 00059 } 00060 00061 /*! 00062 Pointer to the tape identifier for this AD<Base> class and the specific thread. 00063 00064 \tparam Base 00065 is the base type for this AD<Base> class. 00066 00067 \param thread 00068 is the thread number; i.e., 00069 \code 00070 thread == thread_alloc::thread_num() 00071 \endcode 00072 If this condition is not satisfied, and \c NDEBUG is not defined, 00073 a CPPAD_ASSERT_UNKNOWN is generated. 00074 00075 \return 00076 is a pointer to the tape identifier for this thread 00077 and AD<Base> class. 00078 00079 \par Restrictions 00080 This routine should only be called if there was a tape created 00081 for the specified thread (it may no longer be recording). 00082 */ 00083 template <class Base> 00084 inline tape_id_t* AD<Base>::tape_id_ptr(size_t thread) 00085 { CPPAD_ASSERT_UNKNOWN( *tape_id_handle(thread) != CPPAD_NULL ) 00086 return *tape_id_handle(thread); 00087 } 00088 00089 /*! 00090 Handle for the tape for this AD<Base> class and the specific thread. 00091 00092 \tparam Base 00093 is the base type for this AD<Base> class. 00094 00095 00096 \param thread 00097 is the thread number; i.e., 00098 \code 00099 thread == thread_alloc::thread_num() 00100 \endcode 00101 If this condition is not satisfied, and \c NDEBUG is not defined, 00102 a CPPAD_ASSERT_UNKNOWN is generated. 00103 00104 \return 00105 is a handle for the AD<Base> class and the specified thread. 00106 */ 00107 template <class Base> 00108 inline ADTape<Base>** AD<Base>::tape_handle(size_t thread) 00109 { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL; 00110 static ADTape<Base>* tape_table[CPPAD_MAX_NUM_THREADS]; 00111 CPPAD_ASSERT_UNKNOWN( thread == thread_alloc::thread_num() ); 00112 00113 return tape_table + thread; 00114 } 00115 00116 /*! 00117 Pointer for the tape for this AD<Base> class and the current thread. 00118 00119 \code 00120 thread == thread_alloc::thread_num() 00121 \endcode 00122 00123 \tparam Base 00124 is the base type corresponding to AD<Base> operations. 00125 00126 \return 00127 is a pointer to the tape that is currently recording AD<Base> operations 00128 for the current thread. 00129 If this value is \c CPPAD_NULL, there is no tape currently 00130 recording AD<Base> operations for this thread. 00131 */ 00132 template <class Base> 00133 inline ADTape<Base>* AD<Base>::tape_ptr(void) 00134 { size_t thread = thread_alloc::thread_num(); 00135 return *tape_handle(thread); 00136 } 00137 00138 /*! 00139 Pointer for the tape for this AD<Base> class and the specified tape 00140 identifier. 00141 00142 \tparam Base 00143 is the base type corresponding to AD<Base> operations. 00144 00145 \param tape_id 00146 is the identifier for the tape that is currently recording 00147 AD<Base> operations for the current thread. 00148 It must hold that the current thread is 00149 \code 00150 thread = size_t( tape_id % CPPAD_MAX_NUM_THREADS ) 00151 \endcode 00152 and that there is a tape recording AD<Base> operations 00153 for this thread. 00154 If this is not the currently executing thread, 00155 a variable from a different thread is being recorded on the 00156 tape for this thread which is a user error. 00157 00158 \return 00159 is a pointer to the tape that is currently recording AD<Base> operations 00160 for the current thread (and it is not \c CPPAD_NULL). 00161 00162 \par Restrictions 00163 This routine should only be called if there is a tape recording operaitons 00164 for the specified thread. 00165 */ 00166 template <class Base> 00167 inline ADTape<Base>* AD<Base>::tape_ptr(tape_id_t tape_id) 00168 { size_t thread = size_t( tape_id % CPPAD_MAX_NUM_THREADS ); 00169 CPPAD_ASSERT_KNOWN( 00170 thread == thread_alloc::thread_num(), 00171 "Attempt to use an AD variable with two different threads." 00172 ); 00173 CPPAD_ASSERT_UNKNOWN( tape_id == *tape_id_ptr(thread) ); 00174 CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); 00175 return *tape_handle(thread); 00176 } 00177 00178 /*! 00179 Create and delete tapes that record AD<Base> operations for current thread. 00180 00181 \par thread 00182 the current thread is given by 00183 \code 00184 thread = thread_alloc::thread_num() 00185 \endcode 00186 00187 \tparam Base 00188 is the base type corresponding to AD<Base> operations. 00189 00190 \param job 00191 This argument determines if we are creating a new tape, or deleting an 00192 old one. 00193 - \c tape_manage_new : 00194 Creates and a new tape. 00195 It is assumed that there is no tape recording AD<Base> operations 00196 for this thread when \c tape_manage is called. 00197 It the input value of <tt>*tape_id_handle(thread)</tt> is \c CPPAD_NULL, 00198 it will be changed to a non-zero pointer and the corresponding value 00199 of <tt>*tape_id_ptr(thread)</tt> will be set to 00200 <tt>thread + CPPAD_MAX_NUM_THREADS</tt>. 00201 - \c tape_manage_delete : 00202 It is assumed that there is a tape recording AD<Base> operations 00203 for this thread when \c tape_manage is called. 00204 The value of <tt>*tape_id_ptr(thread)</tt> will be advanced by 00205 \c CPPAD_MAX_NUM_THREADS. 00206 00207 00208 \return 00209 - <tt>job == tape_manage_new</tt>: a pointer to the new tape is returned. 00210 - <tt>job == tape_manage_delete</tt>: the value \c CPPAD_NULL is returned. 00211 */ 00212 template <class Base> 00213 ADTape<Base>* AD<Base>::tape_manage(tape_manage_job job) 00214 { CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL 00215 static ADTape<Base>* tape_table[CPPAD_MAX_NUM_THREADS]; 00216 static ADTape<Base> tape_zero; 00217 static tape_id_t tape_id_save[CPPAD_MAX_NUM_THREADS]; 00218 00219 size_t thread = thread_alloc::thread_num(); 00220 if( job == tape_manage_clear ) 00221 { CPPAD_ASSERT_UNKNOWN(thread == 0 && (! thread_alloc::in_parallel())); 00222 for(thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++) 00223 { if( tape_table[thread] != CPPAD_NULL ) 00224 { tape_id_save[thread] = tape_table[thread]->id_; 00225 *tape_id_handle(thread) = &tape_id_save[thread]; 00226 00227 if( thread != 0 ) 00228 delete( tape_table[thread] ); 00229 tape_table[thread] = CPPAD_NULL; 00230 } 00231 } 00232 return CPPAD_NULL; 00233 } 00234 tape_id_t** tape_id = tape_id_handle(thread); 00235 ADTape<Base>** tape = tape_handle(thread); 00236 00237 if( tape_table[thread] == CPPAD_NULL ) 00238 { // allocate separate memroy to avoid false sharing 00239 if( thread == 0 ) 00240 tape_table[thread] = &tape_zero; 00241 else tape_table[thread] = new ADTape<Base>(); 00242 tape_table[thread]->id_ = tape_id_save[thread]; 00243 *tape_id = &tape_table[thread]->id_; 00244 00245 // init tape id > 0 and thread == tape id % CPPAD_MAX_NUM_THREADS 00246 if( **tape_id == 0 ) 00247 **tape_id = thread + CPPAD_MAX_NUM_THREADS; 00248 } 00249 // make sure tape_id_handle(thread) is pointing to the proper place 00250 CPPAD_ASSERT_UNKNOWN( *tape_id == &tape_table[thread]->id_ ); 00251 // make sure tape_id value is valid for this thread 00252 CPPAD_ASSERT_UNKNOWN( 00253 size_t( **tape_id % CPPAD_MAX_NUM_THREADS ) == thread 00254 ); 00255 00256 switch(job) 00257 { case tape_manage_new: 00258 // tape for this thread must be null at the start 00259 CPPAD_ASSERT_UNKNOWN( *tape == CPPAD_NULL ); 00260 *tape = tape_table[thread]; 00261 break; 00262 00263 case tape_manage_delete: 00264 CPPAD_ASSERT_UNKNOWN( *tape == tape_table[thread] ); 00265 CPPAD_ASSERT_KNOWN( 00266 std::numeric_limits<CPPAD_TAPE_ID_TYPE>::max() 00267 - CPPAD_MAX_NUM_THREADS > **tape_id, 00268 "To many different tapes given the type used for " 00269 "CPPAD_TAPE_ID_TYPE" 00270 ); 00271 // advance tape identfier so all AD<Base> variables become parameters 00272 **tape_id += CPPAD_MAX_NUM_THREADS; 00273 // free memory corresponding to recording in the old tape 00274 tape_table[thread]->Rec_.free(); 00275 // inform rest of CppAD that no tape recording for this thread 00276 *tape = CPPAD_NULL; 00277 break; 00278 00279 case tape_manage_clear: 00280 CPPAD_ASSERT_UNKNOWN(false); 00281 } 00282 return *tape; 00283 } 00284 00285 /*! 00286 Get a pointer to tape that records AD<Base> operations for the current thread. 00287 00288 \tparam Base 00289 is the base type corresponding to AD<Base> operations. 00290 00291 \par thread 00292 The current thread must be given by 00293 \code 00294 thread = this->tape_id_ % CPPAD_MAX_NUM_THREADS 00295 \endcode 00296 00297 \return 00298 is a pointer to the tape that is currently recording AD<Base> operations 00299 for the current thread. 00300 This value must not be \c CPPAD_NULL; i.e., there must be a tape currently 00301 recording AD<Base> operations for this thread. 00302 */ 00303 00304 template <class Base> 00305 inline ADTape<Base> *AD<Base>::tape_this(void) const 00306 { 00307 size_t thread = size_t( tape_id_ % CPPAD_MAX_NUM_THREADS ); 00308 CPPAD_ASSERT_UNKNOWN( tape_id_ == *tape_id_ptr(thread) ); 00309 CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); 00310 return *tape_handle(thread); 00311 } 00312 00313 /*! \} */ 00314 CPPAD_END_NAMESPACE 00315 # endif