00001 # ifndef CPPAD_TAPE_LINK_INCLUDED 00002 # define CPPAD_TAPE_LINK_INCLUDED 00003 00004 /* -------------------------------------------------------------------------- 00005 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-07 Bradley M. Bell 00006 00007 CppAD is distributed under multiple licenses. This distribution is under 00008 the terms of the 00009 Common Public License Version 1.0. 00010 00011 A copy of this license is included in the COPYING file of this distribution. 00012 Please visit http://www.coin-or.org/CppAD/ for information on other licenses. 00013 -------------------------------------------------------------------------- */ 00014 /* 00015 $begin tape_link$$ $comment CppAD Developer Documentation$$ 00016 00017 $section Routines that Link AD<Base> and ADTape<Base> Objects$$ 00018 $spell 00019 omp 00020 bool 00021 ptr 00022 const 00023 tbl 00024 atexit 00025 $$ 00026 00027 $head tape_this$$ 00028 $index tape_this$$ 00029 The syntax 00030 $syntax% 00031 %ptr% = %x%.tape_this() 00032 %$$ 00033 returns the tape corresponding to $italic x$$ 00034 where $italic x$$ and $italic ptr$$ have the prototypes 00035 $syntax% 00036 const AD<%Base%> &%x% 00037 ADTape<%Base%> *%ptr% 00038 %$$ 00039 The argument $italic x$$ must a variable. 00040 00041 $head id_handle$$ 00042 $index id_handle$$ 00043 The syntax 00044 $syntax% 00045 %id% = AD<%Base%>::id_handle(%thread%) 00046 %$$ 00047 returns a pointer to the currently active tape identifier 00048 for the specified OpenMP thread. 00049 00050 $subhead thread$$ 00051 The argument $italic thread$$ has prototype 00052 $syntax% 00053 size_t %thread% 00054 %$$ 00055 It must be less that $code CPPAD_MAX_NUM_THREADS$$ and 00056 specifies the OpenMP thread that the tape identifier is for. 00057 In the case where the preprocessor symbol $code _OPENMP$$ is not defined, 00058 $italic thread$$ must be zero. 00059 00060 $subhead id$$ 00061 The return value $italic id$$ has prototype 00062 $syntax% 00063 size_t *%id% 00064 %$$ 00065 and is a pointer to the tape identifier for the specified thread. 00066 The initial value, for the tape identifier is zero. 00067 This way it is not equal to the default $code id_ = 1$$ value 00068 in each $syntax%AD<%Base%>%$$ object. 00069 Either $syntax%*id_handle(%thread%)%$$ is zero (its initial value) or 00070 the current thread number satisfies the equation 00071 $syntax/ 00072 /thread/ == *id_handle(/thread/) % CPPAD_MAX_NUM_THREADS 00073 /$$ 00074 (This is a restriction on how $syntax%*id_handle(%thread%)%$$ may be changed.) 00075 00076 00077 $head tape_handle$$ 00078 $index tape_handle$$ 00079 The syntax 00080 $syntax% 00081 %tape% = AD<%Base%>::tape_handle(%thread%) 00082 %$$ 00083 returns a pointer to a pointer to the current tape 00084 for the specified OpenMP thread. 00085 00086 $subhead thread$$ 00087 The argument $italic thread$$ has prototype 00088 $syntax% 00089 size_t %thread% 00090 %$$ 00091 It must be less that $code CPPAD_MAX_NUM_THREADS$$ and 00092 specifies the OpenMP thread that the tape identifier is for. 00093 In the case where the preprocessor symbol $code _OPENMP$$ is not defined, 00094 $italic thread$$ must be zero. 00095 00096 $subhead tape$$ 00097 The return value $italic tape$$ has prototype 00098 $syntax%% 00099 ADTape<%Base%> **tape 00100 %$$. 00101 If the tape is currently active, 00102 $syntax% 00103 *%tape% != CPPAD_NULL 00104 %$$ 00105 00106 00107 $head tape_new$$ 00108 $index tape_new$$ 00109 The syntax 00110 $syntax% 00111 %id% = AD<%Base%>::tape_new() 00112 %$$ 00113 creates a new tape and returns the corresponding tape identifier. 00114 The resulting tape identifier is not equal to zero, one, or to any 00115 of the previous values return by $code tape_new$$. 00116 In addition, the current thread number is given by 00117 $syntax/ 00118 /thread/ = /id/ % CPPAD_MAX_NUM_THREADS 00119 /$$ 00120 The return value $italic id$$ has prototype 00121 $syntax% 00122 size_t %id% 00123 %$$ 00124 This function is only called by the user $code Independent$$ routine 00125 and hence usage errors can be reported as coming from that routine. 00126 00127 $head tape_delete$$ 00128 $index tape_delete$$ 00129 The syntax 00130 $syntax% 00131 AD<%Base%>::tape_delete(%id%) 00132 %$$ 00133 deletes the tape corresponding to the tape identifier $italic id$$. 00134 The value $syntax%*id_handle(%thread%)%$$ for this thread 00135 is set to a value larger than any previous value returned by 00136 $code tape_new()$$. 00137 00138 $head tape_ptr$$ 00139 $index tape_ptr$$ 00140 The syntax 00141 $syntax% 00142 %ptr% = AD<%Base%>::tape_ptr() 00143 %$$ 00144 returns the a pointer to the tape corresponding to the current thread. 00145 The corresponding tape is active if and only if $syntax%%ptr% == CPPAD_NULL%$$. 00146 The syntax 00147 $syntax% 00148 %ptr% = AD<%Base%>::tape_ptr(%id%) 00149 %$$ 00150 does the same thing but if NDEBUG is not defined, it also check that 00151 the $italic id$$ is the corresponding tape identifier and that $italic ptr$$ 00152 is not equal to $code CPPAD_NULL$$. 00153 The argument $italic id$$ has prototype 00154 $syntax% 00155 size_t %id% 00156 %$$ 00157 00158 00159 $end 00160 ---------------------------------------------------------------------------- 00161 */ 00162 00163 # ifdef _OPENMP 00164 # include <omp.h> 00165 # endif 00166 00167 // BEGIN CppAD namespace 00168 namespace CppAD { 00169 00170 // ---------------------------------------------------------------------- 00171 template <class Base> 00172 inline ADTape<Base> *AD<Base>::tape_this(void) const 00173 { 00174 00175 size_t thread = id_ % CPPAD_MAX_NUM_THREADS; 00176 CPPAD_ASSERT_UNKNOWN( id_ == *id_handle(thread) ); 00177 CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); 00178 return *tape_handle(thread); 00179 00180 # if 0 // old code that did not use OpenMP 00181 CPPAD_ASSERT_UNKNOWN( id_ == *id_handle() ); 00182 CPPAD_ASSERT_UNKNOWN( *tape_handle() != CPPAD_NULL ); 00183 return *tape_handle(); 00184 # endif 00185 00186 } 00187 // ---------------------------------------------------------------------- 00188 // Static functions 00189 // 00190 template <class Base> 00191 inline size_t * AD<Base>::id_handle(size_t thread) 00192 { static size_t id_table[CPPAD_MAX_NUM_THREADS]; 00193 CPPAD_ASSERT_UNKNOWN( 00194 (id_table[thread] == 0) 00195 | (id_table[thread] % CPPAD_MAX_NUM_THREADS == thread) 00196 ); 00197 return id_table + thread; 00198 } 00199 template <class Base> 00200 inline ADTape<Base> ** AD<Base>::tape_handle(size_t thread) 00201 { static ADTape<Base> *tape_table[CPPAD_MAX_NUM_THREADS]; 00202 return tape_table + thread; 00203 } 00204 00205 template <class Base> 00206 size_t AD<Base>::tape_new(void) 00207 { 00208 # ifdef _OPENMP 00209 size_t thread = static_cast<size_t> ( omp_get_thread_num() ); 00210 # else 00211 size_t thread = 0; 00212 # endif 00213 size_t *id = id_handle(thread); 00214 ADTape<Base> **tape = tape_handle(thread); 00215 00216 CPPAD_ASSERT_KNOWN( 00217 thread < omp_max_thread(0), 00218 "Independent: OpenMP thread number is >= omp_max_thread setting" 00219 ); 00220 00221 // initialize so that id > 1 and thread == id % CPPAD_MAX_NUM_THREADS 00222 if( *id == 0 ) 00223 *id = thread + 2 * CPPAD_MAX_NUM_THREADS; 00224 00225 // tape for this thread must be null at the start 00226 CPPAD_ASSERT_UNKNOWN( *tape == CPPAD_NULL ); 00227 *tape = new ADTape<Base>( *id ); 00228 00229 return *id; 00230 } 00231 00232 template <class Base> 00233 void AD<Base>::tape_delete(size_t id_old) 00234 { 00235 size_t thread = id_old % CPPAD_MAX_NUM_THREADS; 00236 # ifdef _OPENMP 00237 CPPAD_ASSERT_KNOWN( 00238 thread == static_cast<size_t> ( omp_get_thread_num() ), 00239 "AD tape recording must stop in same thread as it started in." 00240 ); 00241 # else 00242 CPPAD_ASSERT_UNKNOWN(thread == 0); 00243 # endif 00244 size_t *id = id_handle(thread); 00245 ADTape<Base> **tape = tape_handle(thread); 00246 00247 CPPAD_ASSERT_UNKNOWN( *id == id_old ); 00248 CPPAD_ASSERT_UNKNOWN( *tape != CPPAD_NULL ); 00249 00250 // increase the id for this thread in a way such that 00251 // thread = id % CPPAD_MAX_NUM_THREADS 00252 *id += CPPAD_MAX_NUM_THREADS; 00253 00254 // delete the old tape for this thread 00255 delete ( *tape ); 00256 *tape = CPPAD_NULL; 00257 00258 return; 00259 } 00260 template <class Base> 00261 inline ADTape<Base> *AD<Base>::tape_ptr(void) 00262 { 00263 # ifdef _OPENMP 00264 size_t thread = static_cast<size_t> ( omp_get_thread_num() ); 00265 # else 00266 size_t thread = 0; 00267 # endif 00268 return *tape_handle(thread); 00269 } 00270 00271 template <class Base> 00272 inline ADTape<Base> *AD<Base>::tape_ptr(size_t id) 00273 { 00274 size_t thread = id % CPPAD_MAX_NUM_THREADS; 00275 # ifdef _OPENMP 00276 CPPAD_ASSERT_KNOWN( 00277 thread == static_cast<size_t> ( omp_get_thread_num() ), 00278 "Attempt to use an AD variable in two different OpenMP threads." 00279 ); 00280 # else 00281 CPPAD_ASSERT_UNKNOWN(thread == 0 ); 00282 # endif 00283 CPPAD_ASSERT_UNKNOWN( id == *id_handle(thread) ); 00284 CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL ); 00285 return *tape_handle(thread); 00286 } 00287 00288 } // END CppAD namespace 00289 00290 # endif