CppAD: A C++ Algorithmic Differentiation Package 20110419
|
00001 /* $Id$ */ 00002 # ifndef CPPAD_TAPE_LINK_INCLUDED 00003 # define CPPAD_TAPE_LINK_INCLUDED 00004 00005 /* -------------------------------------------------------------------------- 00006 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-11 Bradley M. Bell 00007 00008 CppAD is distributed under multiple licenses. This distribution is under 00009 the terms of the 00010 Common 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 # ifdef _OPENMP 00017 # include <omp.h> 00018 # endif 00019 00020 # include <cppad/local/define.hpp> 00021 00022 CPPAD_BEGIN_NAMESPACE 00023 /*! 00024 \file tape_link.hpp 00025 Routines that Link AD<Base> and ADTape<Base> Objects \ref tape_link_hpp. 00026 00027 All the routines are AD<Base> member functions and, except for \c tape_this, 00028 they are all static functions. 00029 00030 \defgroup tape_link_hpp tape_link.hpp 00031 */ 00032 /* \{ */ 00033 00034 00035 /*! 00036 Get the identifier for the tape 00037 that records AD<Base> operations for the specified thread. 00038 00039 \tparam Base 00040 is the base type corresponding to AD<Base> operations. 00041 00042 \param thread 00043 is the index that identifes the current OpenMP thread. 00044 <tt>0 <= thread < omp_max_thread(0)</tt>. 00045 00046 \return 00047 The return value \c r 00048 is a pointer to the tape identifier for the current thread. 00049 It can be used to get or set the value of <tt>*r</tt> and 00050 any such setting should abide by the following rules: 00051 \li 00052 Only the routines AD<Base>::tape_new and AD<Base>::tape_delete 00053 change the value of <tt>*r</tt>. 00054 \li 00055 If <tt>*r == 0</tt>, there is no tape currently recording for this thread. 00056 \li 00057 If <tt>*r != 0</tt>, there current is a tape recording for this thread. 00058 Furthermore the identifier satisfies the conditions 00059 <tt>*r > CPPAD_MAX_NUM_THREADS</tt> , and 00060 <tt>*r % CPPAD_MAX_NUM_THREADS == thread</tt>. 00061 \li 00062 The value of <tt>*r</tt> must increase each time it is changed. 00063 */ 00064 template <class Base> 00065 inline size_t * AD<Base>::id_handle(size_t thread) 00066 { // Section 3.6.2 of the 1998 C++ standard specifies that storage for 00067 // static objects will be zero initalized. 00068 static size_t id_table[CPPAD_MAX_NUM_THREADS]; 00069 00070 CPPAD_ASSERT_UNKNOWN( thread < omp_max_thread(0) ); 00071 CPPAD_ASSERT_UNKNOWN( 00072 (id_table[thread] == 0) 00073 | (id_table[thread] % CPPAD_MAX_NUM_THREADS == thread) 00074 ); 00075 return id_table + thread; 00076 } 00077 00078 /*! 00079 Get a handle to the tape 00080 that records AD<Base> operations for the specified thread. 00081 00082 \tparam Base 00083 is the base type corresponding to AD<Base> operations. 00084 00085 \param thread 00086 is the index that identifes the current OpenMP thread. 00087 If \c _OPENMP is not defined, \c thread must be zero. 00088 <tt>0 <= thread < omp_max_thread(0)</tt>. 00089 00090 \return 00091 The return value \c r 00092 is a handle to the tape that records AD<Base> operations 00093 for the current thread. 00094 This can be used to, create, get, or delete, the AD<Base> tape corresponding 00095 to the current thread. 00096 If <tt>*r == CPPAD_NULL</tt>, there is no tape currently 00097 recording AD<Base> operations for the specified thread. 00098 */ 00099 template <class Base> 00100 inline ADTape<Base> ** AD<Base>::tape_handle(size_t thread) 00101 { static ADTape<Base> *tape_table[CPPAD_MAX_NUM_THREADS]; 00102 CPPAD_ASSERT_UNKNOWN( thread < omp_max_thread(0) ); 00103 return tape_table + thread; 00104 } 00105 00106 /*! 00107 Get a pointer to tape 00108 that records AD<Base> operations for the current thread. 00109 00110 \tparam Base 00111 is the base type corresponding to AD<Base> operations. 00112 00113 \par thread 00114 is the index that identifes the current OpenMP thread. 00115 If \c _OPENMP is not defined, \c thread is zero. 00116 <tt>0 <= thread < omp_max_thread(0)</tt>. 00117 00118 \return 00119 The return value \c r is a pointer to the tape that records AD<Base> operations 00120 for the current thread. 00121 If <tt>r == CPPAD_NULL</tt>, there is no tape currently 00122 recording AD<Base> operations for the specified thread. 00123 */ 00124 00125 template <class Base> 00126 inline ADTape<Base> *AD<Base>::tape_ptr(void) 00127 { 00128 # ifdef _OPENMP 00129 size_t thread = static_cast<size_t> ( omp_get_thread_num() ); 00130 # else 00131 size_t thread = 0; 00132 # endif 00133 return *tape_handle(thread); 00134 } 00135 00136 /*! 00137 Get a pointer to tape 00138 that records AD<Base> operations for the current thread. 00139 00140 \tparam Base 00141 is the base type corresponding to AD<Base> operations. 00142 00143 \par thread 00144 is the index that identifes the current OpenMP thread. 00145 If \c _OPENMP is not defined, \c thread is zero. 00146 <tt>0 <= thread < omp_max_thread(0)</tt>. 00147 00148 \param id 00149 is the identifier for the tape that is currently recording 00150 AD<Base> operations for the current thread. 00151 It must hold that <tt>thread = id % CPPAD_MAX_NUM_THREADS</tt>. 00152 Note this routine should be faster when NDEBUG is defined (?) than 00153 calling \c tape_ptr without the \c id argument. 00154 00155 \return 00156 The return value \c r is a pointer to the tape that records AD<Base> operations 00157 for the current thread. 00158 If <tt>r == CPPAD_NULL</tt>, there is no tape currently 00159 recording AD<Base> operations for the specified thread. 00160 */ 00161 template <class Base> 00162 inline ADTape<Base> *AD<Base>::tape_ptr(size_t id) 00163 { 00164 size_t thread = id % CPPAD_MAX_NUM_THREADS; 00165 # ifdef _OPENMP 00166 CPPAD_ASSERT_KNOWN( 00167 thread == static_cast<size_t> ( omp_get_thread_num() ), 00168 "Attempt to use an AD variable in two different OpenMP threads." 00169 ); 00170 # else 00171 CPPAD_ASSERT_UNKNOWN(thread == 0 ); 00172 # endif 00173 CPPAD_ASSERT_UNKNOWN( id == *id_handle(thread) ); 00174 CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); 00175 return *tape_handle(thread); 00176 } 00177 00178 /*! 00179 Create a new tape that records AD<Base> operations for current thread. 00180 00181 \tparam Base 00182 is the base type corresponding to AD<Base> operations. 00183 00184 \par thread 00185 Let \c thread denote the current OpenMP thread number 00186 \c omp_get_thread_num(). 00187 If \c _OPENMP is not defined, \c thread is zero. 00188 It is a user error if <tt>thread >= AD<Base>::omp_max_thread(0)</tt>. 00189 00190 \par tape_handle 00191 It is assumed that <tt>*tape_handle(thread) == CPPAD_NULL</tt> 00192 when \c tape_new is called. 00193 Upon return <tt>*tape_handle(thread)</tt> is a pointer 00194 to the new ADTape<Base> tape that was created. 00195 00196 \par tape_id 00197 We use \c id to denote <tt>AD<Base>::tape_id(thread)</tt>. 00198 If <tt>*id</tt> is zero when \c tape_new is called, 00199 a new value is chosen by \c tape_new. 00200 Otherwise, <tt>*id</tt> is not modified. 00201 00202 \return 00203 The return value \c id is the identifier for the new tape and satisfies 00204 the following conditions: 00205 \li 00206 <tt>id > CPPAD_MAX_NUM_THREADS</tt> 00207 \li 00208 <tt>thread = id % CPPAD_MAX_NUM_THREADS</tt> 00209 \li 00210 Each call to \c tape_new returns a different value \c id. 00211 */ 00212 template <class Base> 00213 size_t AD<Base>::tape_new(void) 00214 { 00215 # ifdef _OPENMP 00216 size_t thread = static_cast<size_t> ( omp_get_thread_num() ); 00217 # else 00218 size_t thread = 0; 00219 # endif 00220 size_t *id = id_handle(thread); 00221 ADTape<Base> **tape = tape_handle(thread); 00222 00223 CPPAD_ASSERT_KNOWN( 00224 thread < omp_max_thread(0), 00225 "Independent: An OpenMP thread number > current omp_max_thread setting.\n" 00226 "Use AD<Base>::omp_max_thread to inform CppAD of the number of threads." 00227 ); 00228 00229 // initialize so that id > 1 and thread == id % CPPAD_MAX_NUM_THREADS 00230 if( *id == 0 ) 00231 *id = thread + 2 * CPPAD_MAX_NUM_THREADS; 00232 // else *id has been set to its new value by tape_delete 00233 00234 // tape for this thread must be null at the start 00235 CPPAD_ASSERT_UNKNOWN( *tape == CPPAD_NULL ); 00236 *tape = new ADTape<Base>( *id ); 00237 00238 return *id; 00239 } 00240 00241 /*! 00242 Delete the tape, and advance the id number, corresponding to AD<Base> 00243 operations for the current thread. 00244 00245 \tparam Base 00246 is the base type corresponding to AD<Base> operations. 00247 00248 \param id_old 00249 Is the identifer for the tape that is recording AD<Base> operations 00250 for this thread. 00251 00252 \par thread 00253 Let \c thread denote the current OpenMP thread number 00254 \c omp_get_thread_num(). 00255 If \c _OPENMP is not defined, \c thread is zero. 00256 It must hold that <tt>thread = id_old % CPPAD_MAX_NUM_THREADS</tt>. 00257 00258 \par tape_handle 00259 It is assumed that <tt>*tape_handle(thread) != CPPAD_NULL</tt> 00260 when \c tape_delete is called; i.e., AD<Base> operations for this 00261 thread are being recorded. 00262 The destructore for the corresponding tape is called and 00263 upon return <tt>*tape_handle(thread) == CPPAD_NULL</tt>. 00264 00265 \par tape_id 00266 We use \c id to denote <tt>AD<Base>::tape_id(thread)</tt>. 00267 Upon the call to \c tape_delete, <tt>*id == id_old</tt>. 00268 Upon the return, 00269 <tt>*id > id_old</tt> and <tt>thread = *id % CPPAD_MAX_NUM_THREADS</tt> 00270 */ 00271 template <class Base> 00272 void AD<Base>::tape_delete(size_t id_old) 00273 { 00274 size_t thread = id_old % CPPAD_MAX_NUM_THREADS; 00275 # ifdef _OPENMP 00276 CPPAD_ASSERT_KNOWN( 00277 thread == static_cast<size_t> ( omp_get_thread_num() ), 00278 "AD tape recording must stop in same thread as it started in." 00279 ); 00280 # else 00281 CPPAD_ASSERT_UNKNOWN(thread == 0); 00282 # endif 00283 size_t *id = id_handle(thread); 00284 ADTape<Base> **tape = tape_handle(thread); 00285 00286 CPPAD_ASSERT_UNKNOWN( *id == id_old ); 00287 CPPAD_ASSERT_UNKNOWN( *tape != CPPAD_NULL ); 00288 00289 // increase the id for this thread in a way such that 00290 // thread = id % CPPAD_MAX_NUM_THREADS 00291 *id += CPPAD_MAX_NUM_THREADS; 00292 00293 // delete the old tape for this thread 00294 delete ( *tape ); 00295 *tape = CPPAD_NULL; 00296 00297 return; 00298 } 00299 00300 /*! 00301 Get a pointer to tape that records AD<Base> operations for the current thread. 00302 00303 \tparam Base 00304 is the base type corresponding to AD<Base> operations. 00305 00306 \par thread 00307 is the index that identifes the current OpenMP thread. 00308 If \c _OPENMP is not defined, \c thread is zero. 00309 <tt>0 <= thread < omp_max_thread(0)</tt>. 00310 00311 \par id_ 00312 This routine uses AD<Base>::id_ to determine the tape identifier 00313 corresponding to the current object. 00314 It must hold that <tt>thread = id_ % CPPAD_MAX_NUM_THREADS</tt>. 00315 Note this routine should be faster when NDEBUG is defined (?) than 00316 calling \c tape_ptr without the \c id argument. 00317 00318 \return 00319 The return value \c r is a pointer to the tape that records AD<Base> operations 00320 for the current thread. 00321 If <tt>r == CPPAD_NULL</tt>, there is no tape currently 00322 recording AD<Base> operations for the specified thread. 00323 */ 00324 00325 template <class Base> 00326 inline ADTape<Base> *AD<Base>::tape_this(void) const 00327 { 00328 00329 size_t thread = id_ % CPPAD_MAX_NUM_THREADS; 00330 CPPAD_ASSERT_UNKNOWN( id_ == *id_handle(thread) ); 00331 CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); 00332 return *tape_handle(thread); 00333 } 00334 00335 /* \} */ 00336 CPPAD_END_NAMESPACE 00337 # endif