source: trunk/cppad/local/player.hpp @ 3941

Last change on this file since 3941 was 3941, checked in by bradbell, 2 years ago

merge to branch: trunk
from repository: https://github.com/coin-or/CppAD
start hash code: b7056a15a1028d7be587b70a3ecc44b1f42dc05e
end hash code: c8c4cc081accff3628e7e66370ec01e4c99afe8d

commit c8c4cc081accff3628e7e66370ec01e4c99afe8d
Author: Brad Bell <bradbell@…>
Date: Thu Jun 1 23:16:39 2017 -0600

Changes automatically generated by the autotools.

commit f4392bc3eee8f6d0ccd45a0bb3be51181e211680
Author: Brad Bell <bradbell@…>
Date: Thu Jun 1 23:11:56 2017 -0600

  1. Add colpack_jac.cpp example (rename colpack_jac.cpp->colpack_jacobian.cpp).
  2. Add colpack_hescpp example (rename colpack_hes.cpp->colpack_hessian.cpp).


test_one.sh.in: adapt to using test_boolofvoid for testing.
sparse_hes.hpp: fix bug in cppad.symmetric case.

commit 086b8a8709b0c9cb01ce2cf8bc7910e903105ff7
Author: Brad Bell <bradbell@…>
Date: Thu Jun 1 08:54:59 2017 -0600

  1. Fix bug in use of colpack (see kludge in comments).
  2. Fix colpack.symmetric (not general) and add colpack.general.
  3. Deprecate colpack.star.
  4. More autotools from install to deprecated.
  5. Advance to cppad-20170601.

commit 23f26c060648f5c6fc62a1598c659aeccc5ca46f
Author: Brad Bell <bradbell@…>
Date: Tue May 30 08:14:04 2017 -0700

Advance to cppad-20170530.

commit 97f8c08509865d1bfb7ec2e5cd557ddc979f8412
Author: Brad Bell <bradbell@…>
Date: Tue May 30 07:38:47 2017 -0700

debug_rel branch:
There is a problem with speed sparse_hessian debug that goes back to master.
Supresss debug in cppad speed tests until it is fixed.

commit 39ea0d7d9c041784ccd26ce80d19a7ab02752818
Author: Brad Bell <bradbell@…>
Date: Mon May 29 22:34:22 2017 -0700

debug_rel branch:
run_cmake.sh: fix debug_none case.
CMakeLists.txt: use cppad_debug_which to determine debug or release.
CMakeLists.txt: let set_compile_flags determkine build type.

commit 191553e54dca407207789cf0d7c6c27fe6188775
Author: Brad Bell <bradbell@…>
Date: Mon May 29 19:53:08 2017 -0700

debug_rel branch:
Use set_compile_flags in introduction.

commit fba276a84e58d9a0d0944168d5706b7446beb32c
Author: Brad Bell <bradbell@…>
Date: Mon May 29 19:46:30 2017 -0700

debug_rel branch:
Use set_compile_flags in eample/multi_thread subdirectories.

commit 66c8cdb266fa3af29b211b8c870a3aed7a13b021
Author: Brad Bell <bradbell@…>
Date: Mon May 29 18:56:48 2017 -0700

debug_rel branch:
Use set_compile_flags in speed directory.

commit c431b15ee7714d3106234bc527ba2f9a836750e1
Author: Brad Bell <bradbell@…>
Date: Mon May 29 18:36:51 2017 -0700

debug_rel branch:
Convert cppad_ipopt to use set_compile_flags and cppad_debug_which.


CMakeLists.txt: alwasy compile for release to reduce testing time.

commit 2c95b0019f1b665fb14b9f00b049e8b5fb11f89d
Author: Brad Bell <bradbell@…>
Date: Mon May 29 16:55:07 2017 -0700

debug_rel branch:
Add cppad_debug_which to the cmake command line.

commit fd8d1498cf6dc092deca41f764cbb2a001a4cc88
Author: Brad Bell <bradbell@…>
Date: Mon May 29 08:14:23 2017 -0700

debug_rel branch:
Change random_debug_release -> set_compile_flags.

commit 159f5a5aa09012213a52f4ed1c9f0607129a5fe7
Author: Brad Bell <bradbell@…>
Date: Mon May 29 06:50:43 2017 -0700

debug_rel branch:
Update the autotools automatically generated build files.


batch_edit.sh: Start comments about a plan for editing all the source files.
get_sacado.sh: advance to trilions-12.10.11.
makefile.am: advance to trilinos-12.10.1

commit 302153317cd296ec6f927c3202cf96bf38594bbb
Author: Brad Bell <bradbell@…>
Date: Mon May 29 05:20:00 2017 -0700

debug_rel branch:
Add error message if sacado configuration file does not exist.

commit 3f01a631ae808c3a1359e53e1cd55e9a0ea88711
Author: Brad Bell <bradbell@…>
Date: Mon May 29 04:24:00 2017 -0700

debug_rel branch:
CMakeLists.txt: automate naming of libraries Sacado needs.
checkpoint.cpp: fix warnings.

commit dd240928c0c8b6972a8197c985ccc01f08b8886b
Author: Brad Bell <bradbell@…>
Date: Sun May 28 08:25:20 2017 -0700

debug_rel branch:
sparse_sub_hes.cpp: add missing cases found by clang compiler.

commit 30a0c35f1ac50ec425be9a2b7b026284026eccd7
Author: Brad Bell <bradbell@…>
Date: Sun May 28 07:57:36 2017 -0700

debug_rel branch:
eigen_cholesky.hpp: fix compiler warning.
harmonic_time.cpp: remove include that is not used.
forward_active.cpp: fix compiler warning.

commit 4876d14e49dc235865b1574fb38a55cf5ea7a422
Author: Brad Bell <bradbell@…>
Date: Sun May 28 06:19:48 2017 -0700

debug_rel branch:
random_debug_release.cmake: fix comment, remove message replaced by random_choice_0123 in output.
multiple_solution.cpp: fix warnings with clang compiler.
eigen_cholesky.hpp: fix warnings with clang compiler.
compare_change.cpp: fix CPPAD_DEBUG_AND_RELEASE case.

commit 2c51a18f35188d04d2f94069382439580e23f4ac
Author: Brad Bell <bradbell@…>
Date: Sat May 27 21:04:37 2017 -0700

debug_rel branch:
Advance version to cppad-20170527.

commit 4500887b362537774b05e954ad2a95b65a7b8ba0
Author: Brad Bell <bradbell@…>
Date: Sat May 27 09:04:56 2017 -0700

debug_rel branch:
Ramdomly select debug or release flags in example directory.


CMakeLists.txt: always debug for multi_threed examples.

commit 140b5269a0b1a30643894e5a7a8c9a5eb1310301
Author: Brad Bell <bradbell@…>
Date: Sat May 27 08:10:51 2017 -0700

debug_rel branch:
Changing how we set all debug and release flags.

commit e6fb2639db1288fb75de4030b5906df1e41756f9
Author: Brad Bell <bradbell@…>
Date: Sat May 27 07:30:24 2017 -0700

debug_rel branch:
Replace use of cppad_extra_debug by CPPAD_DEBUG_AND_RELEASE.

commit fbbfd0f6e94862174a8a7a17308489ffddb28084
Author: Brad Bell <bradbell@…>
Date: Sat May 27 05:55:58 2017 -0700

debug_rel branch:
Improve random selection of which files are build for release or debug.


forward.cpp: use new -DCPPAD_DEBUG_AND_RELEASE flag.

commit 284be366fb5e2f685a0c71ea6a0e3f74584bf187
Author: Brad Bell <bradbell@…>
Date: Thu May 25 07:39:32 2017 -0700

debug_rel branch:
Add test that failed before change to player.


player.hpp: Fix so it has the same size in debug and release more.
checkpoint.cpp: fix warning when compiling for release.
run_cmake.sh: prepare to use random number to switch debug and release set.
CMakeLists.txt: switch to only test debug (for now).

commit f32375b77e3825628fee6cb160f691a32c48b796
Author: Brad Bell <bradbell@…>
Date: Wed May 24 12:04:27 2017 -0700

debug_rel branch:
forward.cpp: fix a warning during release build.

commit 5fcc7eb78ae8de9f1dbc6c4f0c76fe38e8aeba95
Author: Brad Bell <bradbell@…>
Date: Wed May 24 10:11:12 2017 -0700

debug_rel branch:
CMakeLists.txt: make easy to mix debug and release builds.
eigen_mat_inv.hpp: fix release version warning.

commit 696266f3d62079f5e3bfb1a0f60a7e4f8134e068
Author: Brad Bell <bradbell@…>
Date: Wed May 24 05:43:29 2017 -0700

push_git2svn.py: user ./build in place of ./build/work.
testvector.hpp: improve comments about replacing CPPAD_TESTVECTOR.

  • Property svn:keywords set to Id
File size: 32.8 KB
Line 
1// $Id: player.hpp 3941 2017-06-02 05:36:10Z bradbell $
2# ifndef CPPAD_LOCAL_PLAYER_HPP
3# define CPPAD_LOCAL_PLAYER_HPP
4
5/* --------------------------------------------------------------------------
6CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
7
8CppAD is distributed under multiple licenses. This distribution is under
9the terms of the
10                    Eclipse Public License Version 1.0.
11
12A copy of this license is included in the COPYING file of this distribution.
13Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
14-------------------------------------------------------------------------- */
15
16# include <cppad/local/user_state.hpp>
17
18namespace CppAD { namespace local { // BEGIN_CPPAD_LOCAL_NAMESPACE
19/*!
20\file player.hpp
21File used to define the player class.
22*/
23
24
25/*!
26Class used to store and play back an operation sequence recording.
27
28\tparam Base
29These were AD< Base > operations when recorded. Operations during playback
30are done using the type Base .
31*/
32template <class Base>
33class player {
34private:
35        // ----------------------------------------------------------------------
36        // Variables that define the recording
37        // ----------------------------------------------------------------------
38        /// Number of variables in the recording.
39        size_t num_var_rec_;
40
41        /// number of vecad load opeations in the reconding
42        size_t num_load_op_rec_;
43
44        /// Number of VecAD vectors in the recording
45        size_t num_vecad_vec_rec_;
46
47        /// The operators in the recording.
48        pod_vector<CPPAD_OP_CODE_TYPE> op_rec_;
49
50        /// The VecAD indices in the recording.
51        pod_vector<addr_t> vecad_ind_rec_;
52
53        /// The operation argument indices in the recording
54        pod_vector<addr_t> op_arg_rec_;
55
56        /// The parameters in the recording.
57        /// Note that Base may not be plain old data, so use false in consructor.
58        pod_vector<Base> par_rec_;
59
60        /// Character strings ('\\0' terminated) in the recording.
61        pod_vector<char> text_rec_;
62
63        // ----------------------------------------------------------------------
64        // Variables used for iterating thorough operators in the recording
65        // ----------------------------------------------------------------------
66        /// Current operator
67        OpCode op_;
68
69        /// Index in recording corresponding to current operator
70        size_t op_index_;
71
72        /// Current offset of the argument indices in op_arg_rec_
73        const addr_t* op_arg_;
74
75        /// Index for primary (last) variable corresponding to current operator
76        size_t var_index_;
77
78        /// index for the current user atomic function
79        size_t user_index_;
80
81        /// Flag indicating that a special function must be called before next
82        /// This flags is not used when NDEBUG is defined, but kept in this case
83        /// so that debug and release versions of CppAD can be mixed.
84        bool      special_before_next_;
85
86public:
87        // =================================================================
88        /// constructor
89        player(void) :
90        num_var_rec_(0)                                      ,
91        num_load_op_rec_(0)                                  ,
92        op_rec_( std::numeric_limits<addr_t>::max() )        ,
93        vecad_ind_rec_( std::numeric_limits<addr_t>::max() ) ,
94        op_arg_rec_( std::numeric_limits<addr_t>::max() )    ,
95        par_rec_( std::numeric_limits<addr_t>::max() )       ,
96        text_rec_( std::numeric_limits<addr_t>::max() )
97        { }
98
99        // =================================================================
100        /// destructor
101        ~player(void)
102        { }
103
104        // ===============================================================
105        /*!
106        Moving an operation sequence from a recorder to this player
107
108        \param rec
109        the object that was used to record the operation sequence. After this
110        operation, the state of the recording is no longer defined. For example,
111        the pod_vector member variables in this have been swapped with
112         rec .
113        */
114        void get(recorder<Base>& rec)
115        {       size_t i;
116
117                // just set size_t values
118                num_var_rec_        = rec.num_var_rec_;
119                num_load_op_rec_    = rec.num_load_op_rec_;
120
121                // op_rec_
122                op_rec_.swap(rec.op_rec_);
123
124                // vec_ind_rec_
125                vecad_ind_rec_.swap(rec.vecad_ind_rec_);
126
127                // op_arg_rec_
128                op_arg_rec_.swap(rec.op_arg_rec_);
129
130                // par_rec_
131                par_rec_.swap(rec.par_rec_);
132
133                // text_rec_
134                text_rec_.swap(rec.text_rec_);
135
136                // set the number of VecAD vectors
137                num_vecad_vec_rec_ = 0;
138                for(i = 0; i < vecad_ind_rec_.size(); i += vecad_ind_rec_[i] + 1)
139                        num_vecad_vec_rec_++;
140
141                // vecad_ind_rec_ contains size of each VecAD followed by
142                // the parameter indices used to iniialize it.
143                CPPAD_ASSERT_UNKNOWN( i == vecad_ind_rec_.size() );
144        }
145        // ===============================================================
146        /*!
147        Copying an operation sequence from another player to this one
148
149        \param play
150        the object that contains the operatoion sequence to copy.
151        */
152        void operator=(const player& play)
153        {
154                num_var_rec_        = play.num_var_rec_;
155                num_load_op_rec_    = play.num_load_op_rec_;
156                op_rec_             = play.op_rec_;
157                num_vecad_vec_rec_  = play.num_vecad_vec_rec_;
158                vecad_ind_rec_      = play.vecad_ind_rec_;
159                op_arg_rec_         = play.op_arg_rec_;
160                par_rec_            = play.par_rec_;
161                text_rec_           = play.text_rec_;
162        }
163        // ===============================================================
164        /// Erase the recording stored in the player
165        void Erase(void)
166        {
167                num_var_rec_       = 0;
168                num_load_op_rec_   = 0;
169                num_vecad_vec_rec_ = 0;
170
171                op_rec_.erase();
172                vecad_ind_rec_.erase();
173                op_arg_rec_.erase();
174                par_rec_.erase();
175                text_rec_.erase();
176        }
177        // ================================================================
178        // const functions that retrieve infromation from this player
179        // ================================================================
180        /*!
181        \brief
182        fetch an operator from the recording.
183
184        \return
185        the i-th operator in the recording.
186
187        \param i
188        the index of the operator in recording
189        */
190        OpCode GetOp (size_t i) const
191        {       return OpCode(op_rec_[i]); }
192
193        /*!
194        \brief
195        Fetch a VecAD index from the recording.
196
197        \return
198        the i-th VecAD index in the recording.
199
200        \param i
201        the index of the VecAD index in recording
202        */
203        size_t GetVecInd (size_t i) const
204        {       return vecad_ind_rec_[i]; }
205
206        /*!
207        \brief
208        Fetch a parameter from the recording.
209
210        \return
211        the i-th parameter in the recording.
212
213        \param i
214        the index of the parameter in recording
215        */
216        Base GetPar(size_t i) const
217        {       return par_rec_[i]; }
218
219        /*!
220        \brief
221        Fetch entire parameter vector from the recording.
222
223        \return
224        the entire parameter vector.
225
226        */
227        const Base* GetPar(void) const
228        {       return par_rec_.data(); }
229
230        /*!
231        \brief
232        Fetch a '\\0' terminated string from the recording.
233
234        \return
235        the beginning of the string.
236
237        \param i
238        the index where the string begins.
239        */
240        const char *GetTxt(size_t i) const
241        {       CPPAD_ASSERT_UNKNOWN(i < text_rec_.size() );
242                return text_rec_.data() + i;
243        }
244
245        /// Fetch number of variables in the recording.
246        size_t num_var_rec(void) const
247        {       return num_var_rec_; }
248
249        /// Fetch number of vecad load operations
250        size_t num_load_op_rec(void) const
251        {       return num_load_op_rec_; }
252
253        /// Fetch number of operators in the recording.
254        size_t num_op_rec(void) const
255        {       return op_rec_.size(); }
256
257        /// Fetch number of VecAD indices in the recording.
258        size_t num_vec_ind_rec(void) const
259        {       return vecad_ind_rec_.size(); }
260
261        /// Fetch number of VecAD vectors in the recording
262        size_t num_vecad_vec_rec(void) const
263        {       return num_vecad_vec_rec_; }
264
265        /// Fetch number of argument indices in the recording.
266        size_t num_op_arg_rec(void) const
267        {       return op_arg_rec_.size(); }
268
269        /// Fetch number of parameters in the recording.
270        size_t num_par_rec(void) const
271        {       return par_rec_.size(); }
272
273        /// Fetch number of characters (representing strings) in the recording.
274        size_t num_text_rec(void) const
275        {       return text_rec_.size(); }
276
277        /// Fetch a rough measure of amount of memory used to store recording
278        /// (just lengths, not capacities).
279        size_t Memory(void) const
280        {       return op_rec_.size()        * sizeof(OpCode)
281                     + op_arg_rec_.size()    * sizeof(addr_t)
282                     + par_rec_.size()       * sizeof(Base)
283                     + text_rec_.size()      * sizeof(char)
284                     + vecad_ind_rec_.size() * sizeof(addr_t)
285                ;
286        }
287        // =====================================================================
288        // Forward iteration over operations in this player
289        // =====================================================================
290        /*!
291        Start a play back of the recording during a forward sweep.
292
293        Use repeated calls to forward_next to play back one operator at a time.
294
295        \param op [out]
296        The input value of op does not matter. Its output value is the
297        first operator in the recording; i.e., BeginOp.
298
299        \param op_arg [out]
300        The input value of op_arg does not matter. Its output value is the
301        beginning of the vector of argument indices for the first operation;
302        i.e., 0
303
304        \param op_index [out]
305        The input value of op_index does not matter. Its output value
306        is the index of the next first operator in the recording; i.e., 0.
307
308        \param var_index [out]
309        The input value of var_index does not matter. Its output value is the
310        index of the primary (last) result corresponding to the the first
311        operator (which must be a BeginOp); i.e., 0.
312        */
313        void forward_start(
314                OpCode&        op         ,
315                const addr_t*& op_arg     ,
316                size_t&        op_index   ,
317                size_t&        var_index  )
318        {
319                op        = op_          = OpCode( op_rec_[0] );
320                op_arg    = op_arg_      = op_arg_rec_.data();
321                op_index  = op_index_    = 0;
322                var_index = var_index_   = 0;
323# ifndef NDEBUG
324                special_before_next_     = false;
325                CPPAD_ASSERT_UNKNOWN( op_ == BeginOp );
326                CPPAD_ASSERT_NARG_NRES(op_, 1, 1);
327# endif
328                return;
329        }
330
331        /*!
332        Fetch the next operator during a forward sweep.
333
334        Use forward_start to initialize forward play back to the first operator;
335        i.e., the BeginOp at the beginning of the recording.
336        We use the notation forward_routine to denote the set
337        forward_start, forward_next, forward_csum, forward_cskip, forward_user.
338
339        \param op [in,out]
340        The input value of op must be its output value from the
341        previous call to a forward_routine.
342        Its output value is the next operator in the recording.
343        For speed, forward_next does not check for the special cases
344        where op == CSumOp (op == CSkipOp). In this case
345        some of the return values from forward_next must be corrected by a call
346        to forward_csum (forward_cskip).
347        In addition, for speed, extra information that is only used by the
348        UserOp, UsrapOp, UsravOp, UsrrpOp, UsrrvOp operations is not returned
349        for all operations. If this information is needed, then forward_user
350        should be called after each call to forward_next.
351
352        \param op_arg [in,out]
353        The input value of op_arg must be its output value form the
354        previous call to a forward routine.
355        Its output value is the
356        beginning of the vector of argument indices for this operation.
357
358        \param op_index [in,out]
359        The input value of op_index must be its output value form the
360        previous call to a forward routine.
361        Its output value is the index of this operator in the recording.
362        Thus the ouput value following the previous call to forward_start is one.
363        In addition,
364        the output value increases by one with each call to forward_next.
365
366        \param var_index [in,out]
367        The input value of var_index must be its output value form the
368        previous call to a forward routine.
369        Its output value is the
370        index of the primary (last) result corresponding to the operator op.
371        */
372        void forward_next(
373                OpCode&        op         ,
374                const addr_t*& op_arg     ,
375                size_t&        op_index   ,
376                size_t&        var_index  )
377        {
378                CPPAD_ASSERT_UNKNOWN( ! special_before_next_ );
379                CPPAD_ASSERT_UNKNOWN( op_       == op );
380                CPPAD_ASSERT_UNKNOWN( op_arg    == op_arg_ );
381                CPPAD_ASSERT_UNKNOWN( op_index  == op_index_ );
382                CPPAD_ASSERT_UNKNOWN( var_index == var_index_ );
383
384                // index for the next operator
385                op_index    = ++op_index_;
386
387                // first argument for next operator
388                op_arg      = op_arg_    += NumArg(op_);
389
390                // next operator
391                op          = op_         = OpCode( op_rec_[ op_index_ ] );
392
393                // index for last result for next operator
394                var_index   = var_index_ += NumRes(op);
395
396# ifndef NDEBUG
397                special_before_next_ = (op == CSumOp) | (op == CSkipOp);
398                //
399                CPPAD_ASSERT_UNKNOWN( op_arg_rec_.data() <= op_arg_ );
400                CPPAD_ASSERT_UNKNOWN(
401                        op_arg_ + NumArg(op) <= op_arg_rec_.data() + op_arg_rec_.size()
402                );
403                CPPAD_ASSERT_UNKNOWN( var_index_ < num_var_rec_ );
404# endif
405        }
406        /*!
407        Correct forward_next return values when op == CSumOp.
408
409        \param op [in]
410        The input value of op must be the return value from the previous
411        call to forward_next and must be CSumOp. It is not modified.
412
413        \param op_arg [in,out]
414        The input value of op_arg must be the return value from the
415        previous call to forward_next. Its output value is the
416        beginning of the vector of argument indices for the next operation.
417
418        \param op_index [in]
419        The input value of op_index must be the return value from the
420        previous call to forward_next. Its is not modified.
421
422        \param var_index [in]
423        The input value of var_index must be the return value from the
424        previous call to forward_next. It is not modified.
425        */
426        void forward_csum(
427                const OpCode&  op         ,
428                const addr_t*& op_arg     ,
429                const size_t&  op_index   ,
430                const size_t&  var_index  )
431        {
432                CPPAD_ASSERT_UNKNOWN( op_       == op );
433                CPPAD_ASSERT_UNKNOWN( op_arg    == op_arg_ );
434                CPPAD_ASSERT_UNKNOWN( op_index  == op_index_ );
435                CPPAD_ASSERT_UNKNOWN( var_index == var_index_ );
436
437                CPPAD_ASSERT_UNKNOWN( op == CSumOp );
438                CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
439                CPPAD_ASSERT_UNKNOWN(
440                op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ]
441                );
442                /*
443                The only thing that really needs fixing is op_arg_.
444                Actual number of arugments for this operator is
445                        op_arg[0] + op_arg[1] + 4.
446                We must change op_arg_ so that when you add NumArg(CSumOp)
447                you get first argument for next operator in sequence.
448                */
449                op_arg = op_arg_ += op_arg[0] + op_arg[1] + 4;
450
451# ifndef NDEBUG
452                CPPAD_ASSERT_UNKNOWN( special_before_next_ );
453                special_before_next_ = false;
454                //
455                CPPAD_ASSERT_UNKNOWN( op_arg_rec_.data() <= op_arg_ );
456                CPPAD_ASSERT_UNKNOWN(
457                        op_arg_ + NumArg(op) <= op_arg_rec_.data() + op_arg_rec_.size()
458                );
459                CPPAD_ASSERT_UNKNOWN( var_index_ < num_var_rec_ );
460# endif
461        }
462        /*!
463        Correct forward_next return values when op == CSkipOp.
464
465        \param op [in]
466        The input value of op must be the return value from the previous
467        call to forward_next and must be CSkipOp. It is not modified.
468
469        \param op_arg [in,out]
470        The input value of op_arg must be the return value from the
471        previous call to forward_next. Its output value is the
472        beginning of the vector of argument indices for the next operation.
473
474        \param op_index [in]
475        The input value of op_index must be the return value from the
476        previous call to forward_next. Its is not modified.
477
478        \param var_index [in]
479        The input value of var_index must be the return value from the
480        previous call to forward_next. It is not modified.
481        */
482        void forward_cskip(
483                const OpCode&  op         ,
484                const addr_t*& op_arg     ,
485                const size_t&  op_index   ,
486                const size_t&  var_index  )
487        {
488                CPPAD_ASSERT_UNKNOWN( op_       == op );
489                CPPAD_ASSERT_UNKNOWN( op_arg    == op_arg_ );
490                CPPAD_ASSERT_UNKNOWN( op_index  == op_index_ );
491                CPPAD_ASSERT_UNKNOWN( var_index == var_index_ );
492
493                CPPAD_ASSERT_UNKNOWN( op == CSkipOp );
494                CPPAD_ASSERT_UNKNOWN( NumArg(CSkipOp) == 0 );
495                CPPAD_ASSERT_UNKNOWN(
496                op_arg[4] + op_arg[5] == op_arg[ 6 + op_arg[4] + op_arg[5] ]
497                );
498                /*
499                The only thing that really needs fixing is op_arg_.
500                Actual number of arugments for this operator is
501                        7 + op_arg[4] + op_arg[5]
502                We must change op_arg_ so that when you add NumArg(CSkipOp)
503                you get first argument for next operator in sequence.
504                */
505                op_arg = op_arg_ += 7 + op_arg[4] + op_arg[5];
506
507# ifndef NDEBUG
508                CPPAD_ASSERT_UNKNOWN( special_before_next_ );
509                special_before_next_ = false;
510                //
511                CPPAD_ASSERT_UNKNOWN( op_arg_rec_.data() <= op_arg_ );
512                CPPAD_ASSERT_UNKNOWN(
513                        op_arg_ + NumArg(op) <= op_arg_rec_.data() + op_arg_rec_.size()
514                );
515                CPPAD_ASSERT_UNKNOWN( var_index_ < num_var_rec_ );
516# endif
517        }
518        /*!
519        Extra information when forward_next returns one of the following op values:
520        UserOp, UsrapOp, UsravOp, UsrrpOp, UsrrvOp.
521
522        \param op [in]
523        The value of op must be the return value from the previous
524        call to forward_next and one of those listed above.
525
526        \param user_state [in,out]
527        This should be initialized to start_user before each call to
528        forward_start and not otherwise changed by the calling program.
529        Upon return it is the state of the user atomic call as follows:
530        \li start_user next user operator will be UserOp at beginning of a call
531        \li arg_user next operator will be UsrapOp or UsravOp.
532        \li ret_user next operator will be UsrrpOp or UsrrvOp.
533        \li end_user next operator will be UserOp at end of a call
534
535        \param user_old [in,out]
536        This should not be changed by the calling program.
537        Upon return it is the extra information used by the old_atomic interface.
538
539        \param user_m [in,out]
540        This should not be changed by the calling program.
541        Upon return it is the number of results for this user atomic function.
542
543        \param user_n [in,out]
544        This should not be changed by the calling program.
545        Upon return it is the number of arguments to this user atomic function.
546
547        \param user_i [in,out]
548        This should not be changed by the calling program.
549        Upon return it is the index for the next result for this
550        user atomic function; i.e., the next UsrrpOp or UsrrvOp.
551        If there are no more results, the return value is user_m.
552
553        \param user_j [in,out]
554        This should not be changed by the calling program.
555        Upon return it is the index for the next argument for this
556        user atomic function; i.e., the next UsrapOp or UsravOp.
557        If there are no more arguments, the return value is user_n.
558
559        \return
560        the return value is a pointer to the atomic_base<Base> object
561        for the correspnding function. If the corresponding user function
562        has been deleted, an CPPAD_ASSERT_KNOWN is generated and a null pointer
563        is returned.
564
565        \par Initialization
566        The initial value of user_old, user_m, user_n, user_i, user_j
567        do not matter. They may be initialized to avoid compiler warnings.
568        */
569        atomic_base<Base>* forward_user(
570                const OpCode&    op         ,
571                enum_user_state& user_state ,
572                size_t&          user_old   ,
573                size_t&          user_m     ,
574                size_t&          user_n     ,
575                size_t&          user_i     ,
576                size_t&          user_j     )
577        {       atomic_base<Base>* user_atom;
578                switch(op)
579                {
580                        case UserOp:
581                        CPPAD_ASSERT_NARG_NRES(op, 4, 0);
582                        if( user_state == start_user )
583                        {
584                                // forward_user arguments determined by values in UserOp
585                                user_index_ = op_arg_[0];
586                                user_old    = op_arg_[1];
587                                user_n      = op_arg_[2];
588                                user_m      = op_arg_[3];
589                                CPPAD_ASSERT_UNKNOWN( user_n > 0 );
590
591                                // other forward_user arguments
592                                user_j     = 0;
593                                user_i     = 0;
594                                user_state = arg_user;
595
596# ifndef NDEBUG
597                                user_atom = atomic_base<Base>::class_object(user_index_);
598                                if( user_atom == CPPAD_NULL )
599                                {       // user_atom is null so cannot use user_atom->afun_name()
600                                        std::string msg =
601                                                atomic_base<Base>::class_name(user_index_)
602                                                + ": atomic_base function has been deleted";
603                                        CPPAD_ASSERT_KNOWN(false, msg.c_str() );
604                                }
605# endif
606                        }
607                        else
608                        {       // copy of UsrOp at end of this atomic sequence
609                                CPPAD_ASSERT_UNKNOWN( user_state == end_user );
610                                CPPAD_ASSERT_UNKNOWN( user_index_ == size_t(op_arg_[0]) );
611                                CPPAD_ASSERT_UNKNOWN( user_old   == size_t(op_arg_[1]) );
612                                CPPAD_ASSERT_UNKNOWN( user_n     == size_t(op_arg_[2]) );
613                                CPPAD_ASSERT_UNKNOWN( user_m     == size_t(op_arg_[3]) );
614                                CPPAD_ASSERT_UNKNOWN( user_j     == user_n );
615                                CPPAD_ASSERT_UNKNOWN( user_i     == user_m );
616                                user_state = start_user;
617                        }
618                        break;
619
620                        case UsrapOp:
621                        case UsravOp:
622                        CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 );
623                        CPPAD_ASSERT_UNKNOWN( user_state == arg_user );
624                        CPPAD_ASSERT_UNKNOWN( user_i == 0 );
625                        CPPAD_ASSERT_UNKNOWN( user_j < user_n );
626                        ++user_j;
627                        if( user_j == user_n )
628                                user_state = ret_user;
629                        break;
630
631                        case UsrrpOp:
632                        case UsrrvOp:
633                        CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 || op == UsrrvOp );
634                        CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 || op == UsrrpOp );
635                        CPPAD_ASSERT_UNKNOWN( user_state == ret_user );
636                        CPPAD_ASSERT_UNKNOWN( user_i < user_m );
637                        CPPAD_ASSERT_UNKNOWN( user_j == user_n );
638                        ++user_i;
639                        if( user_i == user_m )
640                                user_state = end_user;
641                        break;
642
643                        default:
644                        CPPAD_ASSERT_UNKNOWN(false);
645                }
646                // the atomic_base object corresponding to this user function
647                user_atom = atomic_base<Base>::class_object(user_index_);
648                CPPAD_ASSERT_UNKNOWN( user_atom != CPPAD_NULL );
649                return user_atom;
650        }
651        // =====================================================================
652        // Reverse iteration over operations in this player
653        // =====================================================================
654        /*!
655        Start a play back of the recording during a reverse sweep.
656
657        Use repeated calls to reverse_next to play back one operator at a time.
658
659        \param op [out]
660        The input value of op does not matter. Its output value is the
661        last operator in the recording; i.e., EndOp.
662
663        \param op_arg [out]
664        The input value of op_arg does not matter. Its output value is the
665        beginning of the vector of argument indices for the last operation;
666        (there are no arguments for the last operation so op_arg is invalid).
667
668        \param op_index [out[
669        The input value of op_index does not matter. Its output value
670        is the index of the last operator in the recording.
671
672        \param var_index [out]
673        The input value of var_index does not matter. Its output value is the
674        index of the primary (last) result corresponding to the the last
675        operator (which must be a EndOp).
676        (there are no results for the last operation so var_index is invalid).
677        */
678
679        void reverse_start(
680                OpCode&        op         ,
681                const addr_t*& op_arg     ,
682                size_t&        op_index   ,
683                size_t&        var_index  )
684        {
685                op_arg      = op_arg_     = op_arg_rec_.data() + op_arg_rec_.size();
686                op_index    = op_index_   = op_rec_.size() - 1;
687                var_index   = var_index_  = num_var_rec_ - 1;
688                op          = op_         = OpCode( op_rec_[ op_index_ ] );
689# ifndef NDEBUG
690                special_before_next_ = false;
691                CPPAD_ASSERT_UNKNOWN( op_ == EndOp );
692                CPPAD_ASSERT_NARG_NRES(op, 0, 0);
693# endif
694                return;
695        }
696
697        /*!
698        Fetch the next operator during a reverse sweep.
699
700        Use reverse_start to initialize reverse play back to the last operator;
701        i.e., the EndOp at the end of the recording.
702        We use the notation reverse_routine to denote the set
703        reverse_start, reverse_next, reverse_csum, reverse_cskip, reverse_user.
704
705        \param op [in,out]
706        The input value of op must be its output value from the
707        previous call to a reverse_routine.
708        Its output value is the next operator in the recording (in reverse order).
709        For speed, reverse_next does not check for the special cases
710        where op == CSumOp (op == CSkipOp). In this case
711        some of the return values from reverse_next must be corrected by a call
712        to reverse_csum (reverse_cskip).
713        In addition, for speed, extra information that is only used by the
714        UserOp, UsrapOp, UsravOp, UsrrpOp, UsrrvOp operations is not returned
715        for all operations. If this information is needed, then reverse_user
716        should be called after each call to reverse_next.
717
718        \param op_arg [in,out]
719        The input value of op_arg must be its output value from the
720        previous call to a reverse_routine.
721        Its output value is the
722        beginning of the vector of argument indices for this operation.
723
724        \param op_index [in,out]
725        The input value of op_index must be its output value from the
726        previous call to a reverse_routine.
727        Its output value
728        is the index of this operator in the recording. Thus the output
729        value following the previous call to reverse_start is equal to
730        the number of operators in the recording minus one.
731        In addition, the output value decreases by one with each call to
732        reverse_next.
733        The last operator, BeginOp, sets op_index equal to 0.
734
735        \param var_index [in,out]
736        The input value of var_index must be its output value from the
737        previous call to a reverse_routine.
738        Its output value is the
739        index of the primary (last) result corresponding to the operator op.
740        The last operator sets var_index equal to 0 (corresponding to BeginOp
741        at beginning of operation sequence).
742        */
743        void reverse_next(
744                OpCode&        op         ,
745                const addr_t*& op_arg     ,
746                size_t&        op_index   ,
747                size_t&        var_index  )
748        {
749                CPPAD_ASSERT_UNKNOWN( ! special_before_next_ );
750                CPPAD_ASSERT_UNKNOWN( op_       == op );
751                CPPAD_ASSERT_UNKNOWN( op_arg    == op_arg_ );
752                CPPAD_ASSERT_UNKNOWN( op_index  == op_index_ );
753                CPPAD_ASSERT_UNKNOWN( var_index == var_index_ );
754
755                // index of the last result for the next operator
756                CPPAD_ASSERT_UNKNOWN( var_index_ >= NumRes(op_) );
757                var_index   = var_index_ -= NumRes(op_);
758
759                // next operator
760                CPPAD_ASSERT_UNKNOWN( op_index_  > 0 );
761                op_index    = --op_index_;                                  // index
762                op          = op_         = OpCode( op_rec_[ op_index_ ] ); // value
763
764                // first argument for next operator
765                op_arg      = op_arg_    -= NumArg(op);
766
767# ifndef NDEBUG
768                special_before_next_ = (op == CSumOp) | (op == CSkipOp);
769                //
770                CPPAD_ASSERT_UNKNOWN( op_arg_rec_.data() <= op_arg_ );
771                CPPAD_ASSERT_UNKNOWN(
772                        op_arg_ + NumArg(op) <= op_arg_rec_.data() + op_arg_rec_.size()
773                );
774# endif
775        }
776        /*!
777        Correct reverse_next return values when op == CSumOp.
778
779        \param op [in]
780        The input value of op must be the return value from the previous
781        call to reverse_next and must be CSumOp. It is not modified.
782
783        \param op_arg [in,out]
784        The input value of op_arg must be the return value from the
785        previous call to reverse_next. Its output value is the
786        beginning of the vector of argument indices for this operation.
787
788        \param op_index [in]
789        The input value of op_index must be the return value from the
790        previous call to reverse_next. It is not modified.
791
792        \param var_index [in]
793        The input value of var_index must be the return value from the
794        previous call to reverse_next. It is not modified.
795        */
796
797        void reverse_csum(
798                const OpCode&  op         ,
799                const addr_t*& op_arg     ,
800                const size_t&  op_index   ,
801                const size_t&  var_index  )
802        {
803                CPPAD_ASSERT_UNKNOWN( op_       == op );
804                CPPAD_ASSERT_UNKNOWN( op_arg    == op_arg_ );
805                CPPAD_ASSERT_UNKNOWN( op_index  == op_index_ );
806                CPPAD_ASSERT_UNKNOWN( var_index == var_index_ );
807
808                CPPAD_ASSERT_UNKNOWN( op == CSumOp );
809                CPPAD_ASSERT_UNKNOWN( NumArg(CSumOp) == 0 );
810                /*
811                The variables that need fixing are op_arg_ and op_arg. Currently,
812                op_arg points to the last argument for the previous operator.
813                */
814                // last argument for this csum operation
815                --op_arg;
816                // first argument for this csum operation
817                op_arg = op_arg_ -= (op_arg[0] + 4);
818                // now op_arg points to the first argument for this csum operator
819
820                CPPAD_ASSERT_UNKNOWN(
821                op_arg[0] + op_arg[1] == op_arg[ 3 + op_arg[0] + op_arg[1] ]
822                );
823# ifndef NDEBUG
824                CPPAD_ASSERT_UNKNOWN( special_before_next_ );
825                special_before_next_ = false;
826                //
827                CPPAD_ASSERT_UNKNOWN( op_index_ < op_rec_.size() );
828                CPPAD_ASSERT_UNKNOWN( op_arg_rec_.data() <= op_arg_ );
829                CPPAD_ASSERT_UNKNOWN( var_index_ < num_var_rec_ );
830# endif
831        }
832        /*!
833        Correct reverse_next return values when op == CSkipOp.
834
835        \param op [int]
836        The input value of op must be the return value from the previous
837        call to reverse_next and must be CSkipOp. It is not modified.
838
839        \param op_arg [in,out]
840        The input value of op_arg must be the return value from the
841        previous call to reverse_next. Its output value is the
842        beginning of the vector of argument indices for this operation.
843
844        \param op_index [in]
845        The input value of op_index must be the return value from the
846        previous call to reverse_next. It is not modified.
847
848        \param var_index [in]
849        The input value of var_index must be the return value from the
850        previous call to reverse_next. It is not modified.
851        */
852
853        void reverse_cskip(
854                const OpCode&  op         ,
855                const addr_t*& op_arg     ,
856                const size_t&  op_index   ,
857                const size_t&  var_index  )
858        {
859                CPPAD_ASSERT_UNKNOWN( op_       == op );
860                CPPAD_ASSERT_UNKNOWN( op_arg    == op_arg_ );
861                CPPAD_ASSERT_UNKNOWN( op_index  == op_index_ );
862                CPPAD_ASSERT_UNKNOWN( var_index == var_index_ );
863
864                CPPAD_ASSERT_UNKNOWN( op == CSkipOp );
865                CPPAD_ASSERT_UNKNOWN( NumArg(CSkipOp) == 0 );
866                /*
867                The variables that need fixing are op_arg_ and op_arg. Currently,
868                op_arg points to the last arugment for the previous operator.
869                */
870                // last argument for this cskip operation
871                --op_arg;
872                // first argument for this cskip operation
873                op_arg = op_arg_ -= (op_arg[0] + 7);
874
875                CPPAD_ASSERT_UNKNOWN(
876                op_arg[4] + op_arg[5] == op_arg[ 6 + op_arg[4] + op_arg[5] ]
877                );
878# ifndef NDEBUG
879                CPPAD_ASSERT_UNKNOWN( special_before_next_ );
880                special_before_next_ = false;
881                //
882                CPPAD_ASSERT_UNKNOWN( op_index_ < op_rec_.size() );
883                CPPAD_ASSERT_UNKNOWN( op_arg_rec_.data() <= op_arg_ );
884                CPPAD_ASSERT_UNKNOWN( var_index_ < num_var_rec_ );
885# endif
886        }
887        /*!
888        Extra information when reverse_next returns one of the following op values:
889        UserOp, UsrapOp, UsravOp, UsrrpOp, UsrrvOp.
890
891        \param op [in]
892        The value of op must be the return value from the previous
893        call to reverse_next and one of those listed above.
894
895        \param user_state [in,out]
896        This should be initialized to end_user before each call to
897        reverse_start and not otherwise changed by the calling program.
898        Upon return it is the state of the user atomic call as follows:
899        \li end_user next user operator will be UserOp at end of a call
900        \li ret_user next operator will be UsrrpOp or UsrrvOp.
901        \li arg_user next operator will be UsrapOp or UsravOp.
902        \li start_user next operator will be UserOp at beginning of a call
903
904        \param user_old [in,out]
905        This should not be changed by the calling program.
906        Upon return it is the extra information used by the old_atomic interface.
907
908        \param user_m [in,out]
909        This should not be changed by the calling program.
910        Upon return it is the number of results for this user atomic function.
911
912        \param user_n [in,out]
913        This should not be changed by the calling program.
914        Upon return it is the number of arguments to this user atomic function.
915
916        \param user_i [in,out]
917        This should not be changed by the calling program.
918        Upon return it is the index for this result for this
919        user atomic function; i.e., this UsrrpOp or UsrrvOp.
920        If the input value of user_state is end_user, the return value is user_m.
921
922        \param user_j [in,out]
923        This should not be changed by the calling program.
924        Upon return it is the index for this argument for this
925        user atomic function; i.e., this UsrapOp or UsravOp.
926        If the input value of user_state is end_user, the return value is user_n.
927
928        \return
929        the return value is a pointer to the atomic_base<Base> object
930        for the correspnding function. If the corresponding user function
931        has been deleted, an CPPAD_ASSERT_KNOWN is generated and a null pointer
932        is returned.
933
934        \par Initialization
935        The initial value of user_old, user_m, user_n, user_i, user_j
936        do not matter. They may be initialized to avoid compiler warnings.
937        */
938        atomic_base<Base>* reverse_user(
939                const OpCode&    op         ,
940                enum_user_state& user_state ,
941                size_t&          user_old   ,
942                size_t&          user_m     ,
943                size_t&          user_n     ,
944                size_t&          user_i     ,
945                size_t&          user_j     )
946        {       atomic_base<Base>* user_atom;
947                switch(op)
948                {
949                        case UserOp:
950                        CPPAD_ASSERT_NARG_NRES(op, 4, 0);
951                        if( user_state == end_user )
952                        {
953                                // reverse_user arguments determined by values in UserOp
954                                user_index_ = op_arg_[0];
955                                user_old    = op_arg_[1];
956                                user_n      = op_arg_[2];
957                                user_m      = op_arg_[3];
958                                CPPAD_ASSERT_UNKNOWN( user_n > 0 );
959
960                                // other reverse_user arguments
961                                user_j     = user_n;
962                                user_i     = user_m;
963                                user_state = ret_user;
964
965                                // the atomic_base object corresponding to this user function
966# ifndef NDEBUG
967                                user_atom = atomic_base<Base>::class_object(user_index_);
968                                if( user_atom == CPPAD_NULL )
969                                {       // user_atom is null so cannot use user_atom->afun_name()
970                                        std::string msg =
971                                                atomic_base<Base>::class_name(user_index_)
972                                                + ": atomic_base function has been deleted";
973                                        CPPAD_ASSERT_KNOWN(false, msg.c_str() );
974                                }
975# endif
976                        }
977                        else
978                        {       // copy of UsrOp at end of this atomic sequence
979                                CPPAD_ASSERT_UNKNOWN( user_state == start_user );
980                                CPPAD_ASSERT_UNKNOWN( user_index_ == size_t(op_arg_[0]) );
981                                CPPAD_ASSERT_UNKNOWN( user_old   == size_t(op_arg_[1]) );
982                                CPPAD_ASSERT_UNKNOWN( user_n     == size_t(op_arg_[2]) );
983                                CPPAD_ASSERT_UNKNOWN( user_m     == size_t(op_arg_[3]) );
984                                CPPAD_ASSERT_UNKNOWN( user_j     == 0 );
985                                CPPAD_ASSERT_UNKNOWN( user_i     == 0 );
986                                user_state = end_user;
987                        }
988                        break;
989
990                        case UsrapOp:
991                        case UsravOp:
992                        CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 );
993                        CPPAD_ASSERT_UNKNOWN( user_state == arg_user );
994                        CPPAD_ASSERT_UNKNOWN( user_i == 0 );
995                        CPPAD_ASSERT_UNKNOWN( user_j <= user_n );
996                        CPPAD_ASSERT_UNKNOWN( 0 < user_j );
997                        --user_j;
998                        if( user_j == 0 )
999                                user_state = start_user;
1000                        break;
1001
1002                        case UsrrpOp:
1003                        case UsrrvOp:
1004                        CPPAD_ASSERT_UNKNOWN( NumArg(op) == 1 || op == UsrrvOp );
1005                        CPPAD_ASSERT_UNKNOWN( NumArg(op) == 0 || op == UsrrpOp );
1006                        CPPAD_ASSERT_UNKNOWN( user_state == ret_user );
1007                        CPPAD_ASSERT_UNKNOWN( user_i <= user_m );
1008                        CPPAD_ASSERT_UNKNOWN( user_j == user_n );
1009                        CPPAD_ASSERT_UNKNOWN( 0 < user_i );
1010                        --user_i;
1011                        if( user_i == 0 )
1012                                user_state = arg_user;
1013                        break;
1014
1015                        default:
1016                        CPPAD_ASSERT_UNKNOWN(false);
1017                }
1018                // the atomic_base object corresponding to this user function
1019                user_atom = atomic_base<Base>::class_object(user_index_);
1020                CPPAD_ASSERT_UNKNOWN( user_atom != CPPAD_NULL );
1021                return user_atom;
1022        }
1023
1024};
1025
1026} } // END_CPPAD_lOCAL_NAMESPACE
1027# endif
Note: See TracBrowser for help on using the repository browser.