CppAD: A C++ Algorithmic Differentiation Package  20130102
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-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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines