source: branches/opt_cond_exp/cppad/local/recorder.hpp @ 2978

Last change on this file since 2978 was 2978, checked in by bradbell, 7 years ago

Change conditional skip to skipping operations instead of skipping variables.

  • Property svn:keywords set to Id
File size: 13.7 KB
Line 
1/* $Id: recorder.hpp 2978 2013-10-20 15:38:57Z bradbell $ */
2# ifndef CPPAD_RECORDER_INCLUDED
3# define CPPAD_RECORDER_INCLUDED
4/* --------------------------------------------------------------------------
5CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
6
7CppAD is distributed under multiple licenses. This distribution is under
8the terms of the
9                    Eclipse Public License Version 1.0.
10
11A copy of this license is included in the COPYING file of this distribution.
12Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
13-------------------------------------------------------------------------- */
14# include <cppad/local/hash_code.hpp>
15# include <cppad/local/pod_vector.hpp>
16
17namespace CppAD { // BEGIN_CPPAD_NAMESPACE
18/*!
19\defgroup recorder_hpp recorder.hpp
20\{
21\file recorder.hpp
22File used to define the recorder class.
23*/
24
25/*!
26Class used to store an operation sequence while it is being recorded
27(the operation sequence is copied to the player class for playback).
28
29\tparam Base
30This is an AD< \a Base > operation sequence recording; i.e.,
31it records operations of type AD< \a Base >.
32*/
33template <class Base>
34class recorder {
35        friend class player<Base>;
36
37private:
38        /// offset for this thread in the static hash table
39        const size_t thread_offset_;
40
41        /// Number of variables in the recording.
42        size_t    num_rec_var_;
43
44        /// The operators in the recording.
45        pod_vector<CPPAD_OP_CODE_TYPE> rec_op_;
46
47        /// The VecAD indices in the recording.
48        pod_vector<addr_t> rec_vecad_ind_;
49
50        /// The argument indices in the recording
51        pod_vector<addr_t> rec_op_arg_;
52
53        /// The parameters in the recording.
54        /// Note that Base may not be plain old data, so use false in consructor.
55        pod_vector<Base> rec_par_;
56
57        /// Character strings ('\\0' terminated) in the recording.
58        pod_vector<char> rec_text_;
59// ---------------------- Public Functions -----------------------------------
60public:
61        /// Default constructor
62        recorder(void) : 
63        thread_offset_( thread_alloc::thread_num() * CPPAD_HASH_TABLE_SIZE ) ,
64        num_rec_var_(0)                                      ,
65        rec_op_( std::numeric_limits<addr_t>::max() )        ,
66        rec_vecad_ind_( std::numeric_limits<addr_t>::max() ) ,
67        rec_op_arg_( std::numeric_limits<addr_t>::max() )    ,
68        rec_par_( std::numeric_limits<addr_t>::max() )       ,
69        rec_text_( std::numeric_limits<addr_t>::max() )
70        { }
71
72        /// Destructor
73        ~recorder(void)
74        { }
75
76        /*!
77        Frees all information in recording.
78
79        Frees the operation sequence store in this recording
80        (the operation sequence is empty after this operation).
81        The buffers used to store the current recording are returned
82        to the system (so as to conserve on memory).
83        */
84        void free(void)
85        {       num_rec_var_  = 0;
86                rec_op_.free();
87                rec_vecad_ind_.free();
88                rec_op_arg_.free();
89                rec_par_.free();
90                rec_text_.free();
91        }
92        /// Start recording the next operator in the operation sequence.
93        inline size_t PutOp(OpCode op);
94        /// Add a value to the end of the current vector of VecAD indices.
95        inline size_t PutVecInd(size_t vec_ind);
96        /// Find or add a parameter to the current vector of parameters.
97        inline size_t PutPar(const Base &par);
98        /// Put one operation argument index in the recording
99        inline void PutArg(addr_t arg0); 
100        /// Put two operation argument index in the recording
101        inline void PutArg(addr_t arg0, addr_t arg1); 
102        /// Put three operation argument index in the recording
103        inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2); 
104        /// Put four operation argument index in the recording
105        inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3); 
106        /// Put five operation argument index in the recording
107        inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3,
108                addr_t arg4);
109        /// Put six operation argument index in the recording
110        inline void PutArg(addr_t arg0, addr_t arg1, addr_t arg2, addr_t arg3,
111                addr_t arg4, addr_t arg5);
112        /// Reserve spacke for a specified number or arguments
113        inline addr_t* ReserveArg(size_t n_arg);
114
115        /// Put a character string in the text for this recording.
116        inline size_t PutTxt(const char *text);
117
118        /// Number of variables currently stored in the recording.
119        size_t num_rec_var(void) const
120        {       return num_rec_var_; }
121
122        /// Number of operators currently stored in the recording.
123        size_t num_rec_op(void) const
124        {       return  rec_op_.size(); }
125
126        /// Approximate amount of memory used by the recording
127        size_t Memory(void) const
128        {       return rec_op_.capacity()        * sizeof(CPPAD_OP_CODE_TYPE) 
129                     + rec_vecad_ind_.capacity() * sizeof(size_t)
130                     + rec_op_arg_.capacity()    * sizeof(addr_t)
131                     + rec_par_.capacity()       * sizeof(Base)
132                     + rec_text_.capacity()      * sizeof(char);
133        }
134};
135
136/*!
137Start recording the next operator in the operation sequence.
138
139This sets the op code for the next operation in this recording.
140This call must be followed by putting the corresponding
141\verbatim
142        NumArg(op)
143\endverbatim
144argument indices in the recording.
145
146\param op
147Is the op code corresponding to the the operation that is being
148recorded.
149
150\return
151The return value is the index of the primary (last) variable
152corresponding to the result of this operation.
153The number of variables corresponding to the operation is given by
154\verbatim
155        NumRes(op)
156\endverbatim
157With each call to PutOp
158the return index increases by the number of variables corresponding
159to this call to PutOp.
160This index starts at zero after the default constructor
161and after each call to Erase.
162*/
163template <class Base>
164inline size_t recorder<Base>::PutOp(OpCode op)
165{       size_t i    = rec_op_.extend(1);
166        rec_op_[i]  = static_cast<CPPAD_OP_CODE_TYPE>(op);
167        CPPAD_ASSERT_UNKNOWN( rec_op_.size() == i + 1 );
168
169        // first operator should be a BeginOp and NumRes( BeginOp ) > 0
170        num_rec_var_ += NumRes(op);
171        CPPAD_ASSERT_UNKNOWN( num_rec_var_ > 0 );
172
173        return num_rec_var_ - 1;
174}
175
176/*!
177Add a value to the end of the current vector of VecAD indices.
178
179For each VecAD vector, this routine is used to store the length
180of the vector followed by the parameter index corresponding to each
181value in the vector.
182This value for the elements of the VecAD vector corresponds to the
183beginning of the operation sequence.
184
185\param vec_ind
186is the index to be palced at the end of the vector of VecAD indices.
187
188\return
189is the index in the vector of VecAD indices corresponding to this value.
190This index starts at zero after the recorder default constructor
191and after each call to Erase.
192It increments by one for each call to PutVecInd..
193*/
194template <class Base>
195inline size_t recorder<Base>::PutVecInd(size_t vec_ind)
196{       size_t i          = rec_vecad_ind_.extend(1);
197        rec_vecad_ind_[i] = vec_ind;
198        CPPAD_ASSERT_UNKNOWN( rec_vecad_ind_.size() == i + 1 );
199
200        return i;
201}
202
203/*!
204Find or add a parameter to the current vector of parameters.
205
206\param par
207is the parameter to be found or placed in the vector of parameters.
208
209\return
210is the index in the parameter vector corresponding to this parameter value.
211This value is not necessarily placed at the end of the vector
212(because values that are identically equal may be reused).
213*/
214template <class Base>
215size_t recorder<Base>::PutPar(const Base &par)
216{       static size_t   hash_table[CPPAD_HASH_TABLE_SIZE * CPPAD_MAX_NUM_THREADS];
217        size_t          i;
218        size_t          code;
219
220        CPPAD_ASSERT_UNKNOWN( 
221                thread_offset_ / CPPAD_HASH_TABLE_SIZE
222                == 
223                thread_alloc::thread_num() 
224        );
225
226        // get hash code for this value
227        code = static_cast<size_t>( hash_code(par) );
228        CPPAD_ASSERT_UNKNOWN( code < CPPAD_HASH_TABLE_SIZE );
229
230        // If we have a match, return the parameter index
231        i = hash_table[code + thread_offset_];
232        if( i < rec_par_.size() && IdenticalEqualPar(rec_par_[i], par) )
233                        return i;
234       
235        // place a new value in the table
236        i           = rec_par_.extend(1);
237        rec_par_[i] = par;
238        CPPAD_ASSERT_UNKNOWN( rec_par_.size() == i + 1 );
239
240        // make the hash code point to this new value
241        hash_table[code + thread_offset_] = i;
242
243        // return the parameter index
244        return i;
245}
246// -------------------------- PutArg --------------------------------------
247/*!
248Prototype for putting operation argument indices in the recording.
249
250The following syntax
251\verbatim
252        rec.PutArg(arg0)
253        rec.PutArg(arg0, arg1)
254        .
255        .
256        .
257        rec.PutArg(arg0, arg1, ..., arg5)
258\endverbatim
259places the values passed to PutArg at the current end of the
260operation argument indices for the recording.
261\a arg0 comes before \a arg1, etc.
262The proper number of operation argument indices
263corresponding to the operation code op is given by
264\verbatim
265        NumArg(op)
266\endverbatim
267The number of the operation argument indices starts at zero
268after the default constructor and each call to Erase.
269It increases by the number of indices placed by each call to PutArg.
270*/
271inline void prototype_put_arg(void)
272{       // This routine should not be called
273        CPPAD_ASSERT_UNKNOWN(false);
274}
275/*!
276Put one operation argument index in the recording
277
278\param arg0
279The operation argument index
280
281\copydetails prototype_put_arg
282*/
283template <class Base>
284inline void recorder<Base>::PutArg(addr_t arg0)
285{ 
286        size_t i       = rec_op_arg_.extend(1);
287        rec_op_arg_[i] =  static_cast<addr_t>( arg0 );
288        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
289}
290/*!
291Put two operation argument index in the recording
292
293\param arg0
294First operation argument index.
295
296\param arg1
297Second operation argument index.
298
299\copydetails prototype_put_arg
300*/
301template <class Base>
302inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1)
303{ 
304        size_t i         = rec_op_arg_.extend(2);
305        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
306        rec_op_arg_[i]   =  static_cast<addr_t>( arg1 );
307        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
308}
309/*!
310Put three operation argument index in the recording
311
312\param arg0
313First operation argument index.
314
315\param arg1
316Second operation argument index.
317
318\param arg2
319Third operation argument index.
320
321\copydetails prototype_put_arg
322*/
323template <class Base>
324inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2)
325{ 
326        size_t i         = rec_op_arg_.extend(3);
327        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
328        rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
329        rec_op_arg_[i]   =  static_cast<addr_t>( arg2 );
330        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
331}
332/*!
333Put four operation argument index in the recording
334
335\param arg0
336First operation argument index.
337
338\param arg1
339Second operation argument index.
340
341\param arg2
342Third operation argument index.
343
344\param arg3
345Fourth operation argument index.
346
347\copydetails prototype_put_arg
348*/
349template <class Base>
350inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
351        addr_t arg3)
352{ 
353        size_t i         = rec_op_arg_.extend(4);
354        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
355        rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
356        rec_op_arg_[i++] =  static_cast<addr_t>( arg2 );
357        rec_op_arg_[i]   =  static_cast<addr_t>( arg3 );
358        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
359
360}
361/*!
362Put five operation argument index in the recording
363
364\param arg0
365First operation argument index.
366
367\param arg1
368Second operation argument index.
369
370\param arg2
371Third operation argument index.
372
373\param arg3
374Fourth operation argument index.
375
376\param arg4
377Fifth operation argument index.
378
379\copydetails prototype_put_arg
380*/
381template <class Base>
382inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
383        addr_t arg3, addr_t arg4)
384{ 
385        size_t i         = rec_op_arg_.extend(5);
386        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
387        rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
388        rec_op_arg_[i++] =  static_cast<addr_t>( arg2 );
389        rec_op_arg_[i++] =  static_cast<addr_t>( arg3 );
390        rec_op_arg_[i]   =  static_cast<addr_t>( arg4 );
391        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
392
393}
394/*!
395Put six operation argument index in the recording
396
397\param arg0
398First operation argument index.
399
400\param arg1
401Second operation argument index.
402
403\param arg2
404Third operation argument index.
405
406\param arg3
407Fourth operation argument index.
408
409\param arg4
410Fifth operation argument index.
411
412\param arg5
413Sixth operation argument index.
414
415\copydetails prototype_put_arg
416*/
417template <class Base>
418inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2, 
419        addr_t arg3, addr_t arg4, addr_t arg5)
420{ 
421        size_t i         = rec_op_arg_.extend(6);
422        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
423        rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
424        rec_op_arg_[i++] =  static_cast<addr_t>( arg2 );
425        rec_op_arg_[i++] =  static_cast<addr_t>( arg3 );
426        rec_op_arg_[i++] =  static_cast<addr_t>( arg4 );
427        rec_op_arg_[i]   =  static_cast<addr_t>( arg5 );
428        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
429}
430// --------------------------------------------------------------------------
431/*!
432Reserve space for arguments, but delay placing values there.
433
434\param n_arg
435number of arguements to reserve space for
436
437\return
438point to the first argument; i.e., if arg is the return value,
439arg[0] throught arg[n_arg-1] are the arguments.
440*/
441template <class Base>
442inline addr_t* recorder<Base>::ReserveArg(size_t n_arg)
443{ 
444        size_t i = rec_op_arg_.extend(n_arg);
445        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + n_arg );
446        return rec_op_arg_.data() + i;
447}
448// --------------------------------------------------------------------------
449/*!
450Put a character string in the text for this recording.
451
452\param text
453is a '\\0' terminated character string that is to be put in the
454vector of characters corresponding to this recording.
455The terminator '\\0' will be included.
456
457\return
458is the offset with in the text vector for this recording at which
459the character string starts.
460*/
461template <class Base>
462inline size_t recorder<Base>::PutTxt(const char *text)
463{
464        // determine length of the text including terminating '\0'
465        size_t n = 0;
466        while( text[n] != '\0' )
467                n++;
468        CPPAD_ASSERT_UNKNOWN( n <= 1000 ); 
469        n++;
470        CPPAD_ASSERT_UNKNOWN( text[n-1] == '\0' );
471
472        // copy text including terminating '\0'
473        size_t i = rec_text_.extend(n); 
474        size_t j;
475        for(j = 0; j < n; j++)
476                rec_text_[i + j] = text[j];
477        CPPAD_ASSERT_UNKNOWN( rec_text_.size() == i + n );
478
479        return i;
480}
481// -------------------------------------------------------------------------
482
483
484/*! \} */
485} // END_CPPAD_NAMESPACE
486# endif
Note: See TracBrowser for help on using the repository browser.