CppAD: A C++ Algorithmic Differentiation Package 20110419
tape_link.hpp
Go to the documentation of this file.
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