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

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

Use index instead of pointer because pointer can become invalid when vector grows.

  • Property svn:keywords set to Id
File size: 14.2 KB
Line 
1/* $Id: recorder.hpp 2980 2013-10-20 23:33:35Z 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
113        // Reserve space for a specified number of arguments
114        inline size_t ReserveArg(size_t n_arg);
115
116        // Replace an argument value
117        void ReplaceArg(size_t i_arg, size_t value);
118
119        /// Put a character string in the text for this recording.
120        inline size_t PutTxt(const char *text);
121
122        /// Number of variables currently stored in the recording.
123        size_t num_rec_var(void) const
124        {       return num_rec_var_; }
125
126        /// Number of operators currently stored in the recording.
127        size_t num_rec_op(void) const
128        {       return  rec_op_.size(); }
129
130        /// Approximate amount of memory used by the recording
131        size_t Memory(void) const
132        {       return rec_op_.capacity()        * sizeof(CPPAD_OP_CODE_TYPE) 
133                     + rec_vecad_ind_.capacity() * sizeof(size_t)
134                     + rec_op_arg_.capacity()    * sizeof(addr_t)
135                     + rec_par_.capacity()       * sizeof(Base)
136                     + rec_text_.capacity()      * sizeof(char);
137        }
138};
139
140/*!
141Start recording the next operator in the operation sequence.
142
143This sets the op code for the next operation in this recording.
144This call must be followed by putting the corresponding
145\verbatim
146        NumArg(op)
147\endverbatim
148argument indices in the recording.
149
150\param op
151Is the op code corresponding to the the operation that is being
152recorded.
153
154\return
155The return value is the index of the primary (last) variable
156corresponding to the result of this operation.
157The number of variables corresponding to the operation is given by
158\verbatim
159        NumRes(op)
160\endverbatim
161With each call to PutOp
162the return index increases by the number of variables corresponding
163to this call to PutOp.
164This index starts at zero after the default constructor
165and after each call to Erase.
166*/
167template <class Base>
168inline size_t recorder<Base>::PutOp(OpCode op)
169{       size_t i    = rec_op_.extend(1);
170        rec_op_[i]  = static_cast<CPPAD_OP_CODE_TYPE>(op);
171        CPPAD_ASSERT_UNKNOWN( rec_op_.size() == i + 1 );
172
173        // first operator should be a BeginOp and NumRes( BeginOp ) > 0
174        num_rec_var_ += NumRes(op);
175        CPPAD_ASSERT_UNKNOWN( num_rec_var_ > 0 );
176
177        return num_rec_var_ - 1;
178}
179
180/*!
181Add a value to the end of the current vector of VecAD indices.
182
183For each VecAD vector, this routine is used to store the length
184of the vector followed by the parameter index corresponding to each
185value in the vector.
186This value for the elements of the VecAD vector corresponds to the
187beginning of the operation sequence.
188
189\param vec_ind
190is the index to be palced at the end of the vector of VecAD indices.
191
192\return
193is the index in the vector of VecAD indices corresponding to this value.
194This index starts at zero after the recorder default constructor
195and after each call to Erase.
196It increments by one for each call to PutVecInd..
197*/
198template <class Base>
199inline size_t recorder<Base>::PutVecInd(size_t vec_ind)
200{       size_t i          = rec_vecad_ind_.extend(1);
201        rec_vecad_ind_[i] = vec_ind;
202        CPPAD_ASSERT_UNKNOWN( rec_vecad_ind_.size() == i + 1 );
203
204        return i;
205}
206
207/*!
208Find or add a parameter to the current vector of parameters.
209
210\param par
211is the parameter to be found or placed in the vector of parameters.
212
213\return
214is the index in the parameter vector corresponding to this parameter value.
215This value is not necessarily placed at the end of the vector
216(because values that are identically equal may be reused).
217*/
218template <class Base>
219size_t recorder<Base>::PutPar(const Base &par)
220{       static size_t   hash_table[CPPAD_HASH_TABLE_SIZE * CPPAD_MAX_NUM_THREADS];
221        size_t          i;
222        size_t          code;
223
224        CPPAD_ASSERT_UNKNOWN( 
225                thread_offset_ / CPPAD_HASH_TABLE_SIZE
226                == 
227                thread_alloc::thread_num() 
228        );
229
230        // get hash code for this value
231        code = static_cast<size_t>( hash_code(par) );
232        CPPAD_ASSERT_UNKNOWN( code < CPPAD_HASH_TABLE_SIZE );
233
234        // If we have a match, return the parameter index
235        i = hash_table[code + thread_offset_];
236        if( i < rec_par_.size() && IdenticalEqualPar(rec_par_[i], par) )
237                        return i;
238       
239        // place a new value in the table
240        i           = rec_par_.extend(1);
241        rec_par_[i] = par;
242        CPPAD_ASSERT_UNKNOWN( rec_par_.size() == i + 1 );
243
244        // make the hash code point to this new value
245        hash_table[code + thread_offset_] = i;
246
247        // return the parameter index
248        return i;
249}
250// -------------------------- PutArg --------------------------------------
251/*!
252Prototype for putting operation argument indices in the recording.
253
254The following syntax
255\verbatim
256        rec.PutArg(arg0)
257        rec.PutArg(arg0, arg1)
258        .
259        .
260        .
261        rec.PutArg(arg0, arg1, ..., arg5)
262\endverbatim
263places the values passed to PutArg at the current end of the
264operation argument indices for the recording.
265\a arg0 comes before \a arg1, etc.
266The proper number of operation argument indices
267corresponding to the operation code op is given by
268\verbatim
269        NumArg(op)
270\endverbatim
271The number of the operation argument indices starts at zero
272after the default constructor and each call to Erase.
273It increases by the number of indices placed by each call to PutArg.
274*/
275inline void prototype_put_arg(void)
276{       // This routine should not be called
277        CPPAD_ASSERT_UNKNOWN(false);
278}
279/*!
280Put one operation argument index in the recording
281
282\param arg0
283The operation argument index
284
285\copydetails prototype_put_arg
286*/
287template <class Base>
288inline void recorder<Base>::PutArg(addr_t arg0)
289{ 
290        size_t i       = rec_op_arg_.extend(1);
291        rec_op_arg_[i] =  static_cast<addr_t>( arg0 );
292        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
293}
294/*!
295Put two operation argument index in the recording
296
297\param arg0
298First operation argument index.
299
300\param arg1
301Second operation argument index.
302
303\copydetails prototype_put_arg
304*/
305template <class Base>
306inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1)
307{ 
308        size_t i         = rec_op_arg_.extend(2);
309        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
310        rec_op_arg_[i]   =  static_cast<addr_t>( arg1 );
311        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
312}
313/*!
314Put three operation argument index in the recording
315
316\param arg0
317First operation argument index.
318
319\param arg1
320Second operation argument index.
321
322\param arg2
323Third operation argument index.
324
325\copydetails prototype_put_arg
326*/
327template <class Base>
328inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2)
329{ 
330        size_t i         = rec_op_arg_.extend(3);
331        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
332        rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
333        rec_op_arg_[i]   =  static_cast<addr_t>( arg2 );
334        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
335}
336/*!
337Put four operation argument index in the recording
338
339\param arg0
340First operation argument index.
341
342\param arg1
343Second operation argument index.
344
345\param arg2
346Third operation argument index.
347
348\param arg3
349Fourth operation argument index.
350
351\copydetails prototype_put_arg
352*/
353template <class Base>
354inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
355        addr_t arg3)
356{ 
357        size_t i         = rec_op_arg_.extend(4);
358        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
359        rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
360        rec_op_arg_[i++] =  static_cast<addr_t>( arg2 );
361        rec_op_arg_[i]   =  static_cast<addr_t>( arg3 );
362        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
363
364}
365/*!
366Put five operation argument index in the recording
367
368\param arg0
369First operation argument index.
370
371\param arg1
372Second operation argument index.
373
374\param arg2
375Third operation argument index.
376
377\param arg3
378Fourth operation argument index.
379
380\param arg4
381Fifth operation argument index.
382
383\copydetails prototype_put_arg
384*/
385template <class Base>
386inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2,
387        addr_t arg3, addr_t arg4)
388{ 
389        size_t i         = rec_op_arg_.extend(5);
390        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
391        rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
392        rec_op_arg_[i++] =  static_cast<addr_t>( arg2 );
393        rec_op_arg_[i++] =  static_cast<addr_t>( arg3 );
394        rec_op_arg_[i]   =  static_cast<addr_t>( arg4 );
395        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
396
397}
398/*!
399Put six operation argument index in the recording
400
401\param arg0
402First operation argument index.
403
404\param arg1
405Second operation argument index.
406
407\param arg2
408Third operation argument index.
409
410\param arg3
411Fourth operation argument index.
412
413\param arg4
414Fifth operation argument index.
415
416\param arg5
417Sixth operation argument index.
418
419\copydetails prototype_put_arg
420*/
421template <class Base>
422inline void recorder<Base>::PutArg(addr_t arg0, addr_t arg1, addr_t arg2, 
423        addr_t arg3, addr_t arg4, addr_t arg5)
424{ 
425        size_t i         = rec_op_arg_.extend(6);
426        rec_op_arg_[i++] =  static_cast<addr_t>( arg0 );
427        rec_op_arg_[i++] =  static_cast<addr_t>( arg1 );
428        rec_op_arg_[i++] =  static_cast<addr_t>( arg2 );
429        rec_op_arg_[i++] =  static_cast<addr_t>( arg3 );
430        rec_op_arg_[i++] =  static_cast<addr_t>( arg4 );
431        rec_op_arg_[i]   =  static_cast<addr_t>( arg5 );
432        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + 1 );
433}
434// --------------------------------------------------------------------------
435/*!
436Reserve space for arguments, but delay placing values there.
437
438\param n_arg
439number of arguements to reserve space for
440
441\return
442is the index in the argument vector corresponding to the
443first of the arguments being reserved.
444*/
445template <class Base>
446inline size_t recorder<Base>::ReserveArg(size_t n_arg)
447{ 
448        size_t i = rec_op_arg_.extend(n_arg);
449        CPPAD_ASSERT_UNKNOWN( rec_op_arg_.size() == i + n_arg );
450        return i;
451}
452
453/*!
454\brief
455Replace an argument value in the recording
456(intended to fill in reserved values).
457
458\param i_arg
459is the index, in argument vector, for the value that is replaced.
460
461\param value
462is the new value for the argument with the specified index.
463*/
464template <class Base>
465inline void recorder<Base>::ReplaceArg(size_t i_arg, size_t value)
466{       rec_op_arg_[i_arg] =  static_cast<addr_t>( value ); }
467// --------------------------------------------------------------------------
468/*!
469Put a character string in the text for this recording.
470
471\param text
472is a '\\0' terminated character string that is to be put in the
473vector of characters corresponding to this recording.
474The terminator '\\0' will be included.
475
476\return
477is the offset with in the text vector for this recording at which
478the character string starts.
479*/
480template <class Base>
481inline size_t recorder<Base>::PutTxt(const char *text)
482{
483        // determine length of the text including terminating '\0'
484        size_t n = 0;
485        while( text[n] != '\0' )
486                n++;
487        CPPAD_ASSERT_UNKNOWN( n <= 1000 ); 
488        n++;
489        CPPAD_ASSERT_UNKNOWN( text[n-1] == '\0' );
490
491        // copy text including terminating '\0'
492        size_t i = rec_text_.extend(n); 
493        size_t j;
494        for(j = 0; j < n; j++)
495                rec_text_[i + j] = text[j];
496        CPPAD_ASSERT_UNKNOWN( rec_text_.size() == i + n );
497
498        return i;
499}
500// -------------------------------------------------------------------------
501
502
503/*! \} */
504} // END_CPPAD_NAMESPACE
505# endif
Note: See TracBrowser for help on using the repository browser.