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