source: trunk/cppad/local/recorder.hpp @ 3232

Last change on this file since 3232 was 3232, checked in by bradbell, 6 years ago

Remove doxygen \{ commands from old grouping of file entries (corresponding \}
commands alread removed).

doxy_member.sh: Trying to figure out why certain member documentation missing.

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