source: trunk/cppad/local/atomic_base.hpp @ 2903

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

Add lines from atomic_base documentation to corresponding examples.

package.sh: ignore the bug/build directory.

  • Property svn:keywords set to Id
File size: 37.8 KB
Line 
1/* $Id: atomic_base.hpp 2903 2013-09-19 15:53:13Z bradbell $ */
2# ifndef CPPAD_ATOMIC_BASE_INCLUDED
3# define CPPAD_ATOMIC_BASE_INCLUDED
4
5/* --------------------------------------------------------------------------
6CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 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 <set>
17# include <cppad/local/cppad_assert.hpp>
18// needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
19# include <cppad/thread_alloc.hpp>
20
21CPPAD_BEGIN_NAMESPACE
22/*!
23\defgroup atomic_base.hpp atomic_base.hpp
24\{
25\file atomic_base.hpp
26Base class for atomic user operations.
27*/
28
29template <class Base>
30class atomic_base {
31// ===================================================================
32public:
33        enum option_enum { bool_sparsity_enum, set_sparsity_enum};
34private:
35        // ------------------------------------------------------
36        // constants
37        //
38        /// index of this object in class_object
39        const size_t index_;
40
41        // -----------------------------------------------------
42        // variables
43        //
44        /// sparsity pattern this object is currently using
45        /// (set by constructor and option member functions)
46        option_enum sparsity_;
47
48        /// temporary work space used afun, declared here to avoid memory
49        /// allocation/deallocation for each call to afun
50        vector<bool>  afun_vx_[CPPAD_MAX_NUM_THREADS];
51        vector<bool>  afun_vy_[CPPAD_MAX_NUM_THREADS];
52        vector<Base>  afun_tx_[CPPAD_MAX_NUM_THREADS];
53        vector<Base>  afun_ty_[CPPAD_MAX_NUM_THREADS];
54
55        // -----------------------------------------------------
56        // static member functions
57        //
58        /// List of all the object in this class
59        static std::vector<atomic_base *>& class_object(void)
60        {       CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
61                static std::vector<atomic_base *> list_;
62                return list_;
63        }
64        /// List of names for each object in this class
65        static std::vector<std::string>& class_name(void)
66        {       CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL;
67                static std::vector<std::string> list_;
68                return list_;
69        }
70        // =====================================================================
71public:
72        // -----------------------------------------------------
73        // member functions not in user API
74        //
75        /// current sparsity setting
76        option_enum sparsity(void) const
77        {       return sparsity_; }
78
79        /// Name corresponding to a base_atomic object
80        const std::string& afun_name(void) const
81        {       return class_name()[index_]; }
82/*
83$begin atomic_ctor$$
84$spell
85        std
86        afun
87        arg
88        CppAD
89        bool
90        ctor
91        const
92        matrix_mul.hpp
93$$
94
95$section Atomic Function Constructor$$
96$index constructor, atomic function$$
97$index atomic, function constructor$$
98$index function, atomic constructor$$
99
100$head Syntax$$
101$icode%atomic_user afun%(%ctor_arg_list%)
102%$$
103$codei%atomic_base<%Base%>(%name%)
104%$$
105
106$head atomic_user$$
107
108$subhead ctor_arg_list$$
109Is a list of arguments for the $icode atomic_user$$ constructor.
110
111$subhead afun$$
112The object $icode afun$$ must stay in scope for as long
113as the corresponding atomic function is used.
114This includes use by any $cref/ADFun<Base>/ADFun/$$ that
115has this $icode atomic_user$$ operation in its
116$cref/operation sequence/glossary/Operation/Sequence/$$.
117
118$subhead Implementation$$
119The user defined $icode atomic_user$$ class is a publicly derived class of
120$codei%atomic_base<%Base%>%$$.
121It should be declared as follows:
122$codei%
123        class %atomic_user% : public CppAD::atomic_base<%Base%> {
124        public:
125                %atomic_user%(%ctor_arg_list%) : atomic_base<%Base%>(%name%)
126        %...%
127        };
128%$$
129where $icode ...$$ 
130denotes the rest of the implementation of the derived class.
131This includes completing the constructor and
132all the virtual functions that have their
133$code atomic_base$$ implementations replaced by
134$icode atomic_user$$ implementations.
135
136$head atomic_base$$
137
138$subhead Restrictions$$
139The $code atomic_base$$ constructor cannot be called in
140$cref/parallel/ta_in_parallel/$$ mode.
141
142$subhead Base$$
143The template parameter determines the
144$icode Base$$ type for this $codei%AD<%Base%>%$$ atomic operation.
145
146$subhead name$$
147This $icode atomic_base$$ constructor argument has either of the
148following prototypes
149$codei%
150        const char*        %name%
151        const std::string& %name%
152%$$
153It is the name for this atomic function and is used for error reporting.
154The suggested value for $icode name$$ is $icode afun$$ or $icode atomic_user$$,
155i.e., the name of the corresponding atomic object or class.
156
157$head Examples$$
158The following files contain example user atomic function constructors:
159$cref%get_started.cpp%atomic_get_started.cpp%Constructor%$$,
160$cref%reciprocal.cpp%atomic_reciprocal.cpp%Constructor%$$,
161$cref%tangent.cpp%atomic_tangent.cpp%Constructor%$$,
162$cref%matrix_mul.hpp%atomic_matrix_mul.hpp%Constructor%$$.
163
164
165$end
166*/
167/*!
168Base class for atomic_user functions.
169
170\tparam Base
171This class is used for defining an AD<Base> atomic operation y = f(x).
172*/
173/// make sure user does not invoke the default constructor
174atomic_base(void)
175{       CPPAD_ASSERT_KNOWN(false,
176                "Attempt to use the atomic_base default constructor"
177        );
178}
179/*!
180Constructor
181
182\param name
183name used for error reporting
184*/
185atomic_base( const std::string&  name) :
186index_( class_object().size() )     ,
187sparsity_( set_sparsity_enum )
188{       CPPAD_ASSERT_KNOWN(
189                ! thread_alloc::in_parallel() ,
190                "atomic_base: constructor cannot be called in parallel mode."
191        );
192        class_object().push_back(this);
193        class_name().push_back(name);
194        CPPAD_ASSERT_UNKNOWN( class_object().size() == class_name().size() );
195}
196/// destructor informs CppAD that this atomic function with this index
197/// has dropped out of scope by setting its pointer to null
198virtual ~atomic_base(void)
199{       CPPAD_ASSERT_UNKNOWN( class_object().size() > index_ );
200        // change object pointer to null, but leave name for error reporting
201        class_object()[index_] = CPPAD_NULL;
202}
203/// atomic_base function object corresponding to a certain index
204static atomic_base* class_object(size_t index)
205{       CPPAD_ASSERT_UNKNOWN( class_object().size() > index );
206        return class_object()[index];
207}
208/// atomic_base function name corresponding to a certain index
209static const std::string& class_name(size_t index)
210{       CPPAD_ASSERT_UNKNOWN( class_name().size() > index );
211        return class_name()[index];
212}
213/*
214$begin atomic_option$$
215$spell
216        enum
217        afun
218        bool
219        CppAD
220        std
221        typedef
222$$
223
224$section Set Atomic Function Options$$
225$index atomic, options$$
226$index options, atomic$$
227
228$head Syntax$$
229$icode%afun%.option(%option_value%)%$$
230
231$head atomic_sparsity$$
232$index atomic_sparsity$$
233$index sparsity, atomic$$
234You can used this option to set to type used for
235$icode afun$$ sparsity patterns.
236This does not apply individual calls to $icode afun$$,
237but rather all its uses between when the sparsity pattern is set and when
238it is changed.
239If neither the $code set_sparsity_enum$$ or
240$code bool_sparsity_enum$$ option is set,
241the type for $icode atomic_sparsity$$ is one of the two choices below
242(and otherwise unspecified).
243
244$subhead bool_sparsity_enum$$
245$index bool_sparsity_enum$$
246If $icode option_value$$ is $code atomic_base::bool_sparsity_enum$$,
247then the type used by $icode afun$$ for
248$cref/sparsity patterns/glossary/Sparsity Pattern/$$,
249(after the option is set) will be
250$codei%
251        typedef CppAD::vector<bool> %atomic_sparsity%
252%$$
253If $icode r$$ is a sparsity pattern
254for a matrix $latex R \in B^{p \times q}$$:
255$icode%r%.size() == %p% * %q%$$.
256
257$subhead set_sparsity_enum$$
258$index set_sparsity_enum$$
259If $icode option_value$$ is $code atomic_base::set_sparsity_enum$$,
260then the type used by $icode afun$$ for
261$cref/sparsity patterns/glossary/Sparsity Pattern/$$,
262(after the option is set) will be
263$codei%
264        typedef CppAD::vector< std::set<size_t> > %atomic_sparsity%
265%$$
266If $icode r$$ is a sparsity pattern
267for a matrix $code R \in B^{p \times q}$$:
268$icode%r%.size() == %p%$$, and for $latex i = 0 , \ldots , p-1$$,
269the elements of $icode%r%[%i%]%$$ are between zero and $latex q-1$$ inclusive.
270
271$end
272*/
273void option(enum option_enum option_value)
274{       switch( option_value )
275        {       case bool_sparsity_enum:
276                case set_sparsity_enum:
277                sparsity_ = option_value;
278                break;
279
280                default:
281                CPPAD_ASSERT_KNOWN(
282                        false,
283                        "atoic_base::option: option_value is not valid"
284                );
285        }
286        return;
287}
288/*
289-----------------------------------------------------------------------------
290$begin atomic_afun$$
291
292$spell
293        afun
294        const
295        CppAD
296$$
297
298$section Using an Atomic Function$$
299$index atomic, use function$$
300
301$head Syntax$$
302$icode%afun%(%ax%, %ay%)%$$
303
304$head Purpose$$
305Given $icode ax$$,
306this call computes the corresponding value of $icode ay$$.
307If $codei%AD<%Base%>%$$ operations are being recorded,
308it enters the computation as an atomic operation in the recording;
309see $cref/start recording/Independent/Start Recording/$$.
310
311$head ADVector$$
312The type $icode ADVector$$ must be a
313$cref/simple vector class/SimpleVector/$$ with elements of type
314$codei%AD<%Base%>%$$; see $cref/Base/atomic_ctor/atomic_base/Base/$$.
315
316$head afun$$
317is a $cref/atomic_user/atomic_ctor/atomic_user/$$ object
318and this $icode afun$$ function call is implemented by the
319$cref/atomic_base/atomic_ctor/atomic_base/$$ class.
320
321$head ax$$
322This argument has prototype
323$codei%
324        const %ADVector%& %ax%
325%$$
326and size must be equal to $icode n$$.
327It specifies vector $latex x \in B^n$$
328at which an $codei%AD<%Base%>%$$ version of
329$latex y = f(x)$$ is to be evaluated; see
330$cref/Base/atomic_ctor/atomic_base/Base/$$.
331
332$head ay$$
333This argument has prototype
334$codei%
335        %ADVector%& %ay%
336%$$
337and size must be equal to $icode m$$.
338The input values of its elements
339are not specified (must not matter).
340Upon return, it is an $codei%AD<%Base%>%$$ version of
341$latex y = f(x)$$.
342
343$end
344-----------------------------------------------------------------------------
345*/
346/*!
347Implement the user call to <tt>afun(ax, ay)</tt> and old_atomic call to
348<tt>afun(ax, ay, id)</tt>.
349
350\tparam ADVector
351A simple vector class with elements of type <code>AD<Base></code>.
352
353\param id
354optional extra information vector that is just passed through by CppAD,
355and used by old_atomic derived class (not other derived classes).
356This is an extra parameter to the virtual callbacks for old_atomic;
357see the set_id member function.
358
359\param ax
360is the argument vector for this call,
361<tt>ax.size()</tt> determines the number of arguments.
362
363\param ay
364is the result vector for this call,
365<tt>ay.size()</tt> determines the number of results.
366*/
367template <class ADVector>
368void operator()(
369        const ADVector&  ax     ,
370              ADVector&  ay     ,
371        size_t           id = 0 )
372{       size_t i, j;
373        size_t n = ax.size();
374        size_t m = ay.size();
375# ifndef NDEBUG
376        bool ok;
377        std::string msg = "atomic_base: " + afun_name() + ".eval: ";
378        if( (n == 0) | (m == 0) )
379        {       msg += "ax.size() or ay.size() is zero";
380                CPPAD_ASSERT_KNOWN(false, msg.c_str() );
381        }
382# endif
383        size_t thread = thread_alloc::thread_num();
384        vector <Base>& tx  = afun_tx_[thread];
385        vector <Base>& ty  = afun_ty_[thread];
386        vector <bool>& vx  = afun_vx_[thread];
387        vector <bool>& vy  = afun_vy_[thread];
388        //
389        if( vx.size() != n )
390        {       vx.resize(n);
391                tx.resize(n);
392        }
393        if( vy.size() != m )
394        {       vy.resize(m);
395                ty.resize(m);
396        }
397        //
398        // Determine tape corresponding to variables in ax
399        tape_id_t     tape_id  = 0;
400        ADTape<Base>* tape     = CPPAD_NULL;
401        for(j = 0; j < n; j++)
402        {       tx[j]  = ax[j].value_;
403                vx[j]  = Variable( ax[j] );
404                if( vx[j] )
405                {
406                        if( tape_id == 0 )
407                        {       tape    = ax[j].tape_this();
408                                tape_id = ax[j].tape_id_;
409                                CPPAD_ASSERT_UNKNOWN( tape != CPPAD_NULL );
410                        }
411# ifndef NDEBUG
412                        if( tape_id != ax[j].tape_id_ )
413                        {       msg += afun_name() + 
414                                ": ax contains variables from different threads.";
415                                CPPAD_ASSERT_KNOWN(false, msg.c_str());
416                        }
417# endif
418                }
419        }
420        // Use zero order forward mode to compute values
421        size_t q = 0, p = 0;
422        set_id(id);
423# ifdef NDEBUG
424        forward(q, p, vx, vy, tx, ty); 
425# else
426        ok = forward(q, p, vx, vy, tx, ty); 
427        if( ! ok )
428        {       msg += afun_name() + ": ok is false for "
429                        "zero order forward mode calculation.";
430                CPPAD_ASSERT_KNOWN(false, msg.c_str());
431        }
432# endif
433        bool record_operation = false;
434        for(i = 0; i < m; i++)
435        {
436                // pass back values
437                ay[i].value_ = ty[i];
438
439                // initialize entire vector parameters (not in tape)
440                ay[i].tape_id_ = 0;
441                ay[i].taddr_   = 0;
442
443                // we need to record this operation if
444                // any of the eleemnts of ay are variables,
445                record_operation |= vy[i];
446        }
447# ifndef NDEBUG
448        if( record_operation & (tape == CPPAD_NULL) )
449        {       msg += 
450                "all elements of vx are false but vy contains a true element";
451                CPPAD_ASSERT_KNOWN(false, msg.c_str() );
452        }
453# endif
454        // if tape is not null, ay is on the tape
455        if( record_operation )
456        {
457                // Operator that marks beginning of this atomic operation
458                CPPAD_ASSERT_UNKNOWN( NumRes(UserOp) == 0 );
459                CPPAD_ASSERT_UNKNOWN( NumArg(UserOp) == 4 );
460                tape->Rec_.PutArg(index_, id, n, m);
461                tape->Rec_.PutOp(UserOp);
462
463                // Now put n operators, one for each element of arugment vector
464                CPPAD_ASSERT_UNKNOWN( NumRes(UsravOp) == 0 );
465                CPPAD_ASSERT_UNKNOWN( NumRes(UsrapOp) == 0 );
466                CPPAD_ASSERT_UNKNOWN( NumArg(UsravOp) == 1 );
467                CPPAD_ASSERT_UNKNOWN( NumArg(UsrapOp) == 1 );
468                for(j = 0; j < n; j++)
469                {       if( vx[j] )
470                        {       // information for an argument that is a variable
471                                tape->Rec_.PutArg(ax[j].taddr_);
472                                tape->Rec_.PutOp(UsravOp);
473                        }
474                        else
475                        {       // information for an arugment that is parameter
476                                addr_t par = tape->Rec_.PutPar(ax[j].value_);
477                                tape->Rec_.PutArg(par);
478                                tape->Rec_.PutOp(UsrapOp);
479                        }
480                }
481
482                // Now put m operators, one for each element of result vector
483                CPPAD_ASSERT_UNKNOWN( NumArg(UsrrpOp) == 1 );
484                CPPAD_ASSERT_UNKNOWN( NumRes(UsrrpOp) == 0 );
485                CPPAD_ASSERT_UNKNOWN( NumArg(UsrrvOp) == 0 );
486                CPPAD_ASSERT_UNKNOWN( NumRes(UsrrvOp) == 1 );
487                for(i = 0; i < m; i++)
488                {       if( vy[i] )
489                        {       ay[i].taddr_    = tape->Rec_.PutOp(UsrrvOp);
490                                ay[i].tape_id_  = tape_id;
491                        }
492                        else
493                        {       addr_t par = tape->Rec_.PutPar(ay[i].value_);
494                                tape->Rec_.PutArg(par);
495                                tape->Rec_.PutOp(UsrrpOp);
496                        }
497                }
498
499                // Put a duplicate UserOp at end of UserOp sequence
500                tape->Rec_.PutArg(index_, id, n, m);
501                tape->Rec_.PutOp(UserOp);
502        } 
503        return;
504}
505/*
506-----------------------------------------------------------------------------
507$begin atomic_forward$$
508$spell
509        mul.hpp
510        hes
511        afun
512        vx
513        vy
514        ty
515        Taylor
516        const
517        CppAD
518        bool
519$$
520
521$section Atomic Forward Mode$$
522$index atomic, forward callback$$
523$index forward, atomic callback$$
524$index forward, atomic virtual$$
525
526
527$head Syntax$$
528$icode%ok% = %afun%.forward(%q%, %p%, %vx%, %vy%, %tx%, %ty%)%$$
529
530$head Purpose$$
531This virtual function is used by $cref atomic_afun$$
532to evaluate function values.
533It is also used buy $cref/forward/Forward/$$
534to compute function vales and derivatives.
535
536$head Implementation$$
537This virtual function must be defined by the
538$cref/atomic_user/atomic_ctor/atomic_user/$$ class.
539It can just return $icode%ok% == false%$$
540(and not compute anything) for values
541of $icode%p% > 0%$$ that are greater than those used by your
542$cref/forward/Forward/$$ mode calculations.
543
544$head q$$
545The argument $icode q$$ has prototype
546$codei%
547        size_t %q%
548%$$
549It specifies the lowest order Taylor coefficient that we are evaluating.
550During calls to $cref atomic_afun$$, $icode%q% == 0%$$.
551
552$head p$$
553The argument $icode p$$ has prototype
554$codei%
555        size_t %p%
556%$$
557It specifies the highest order Taylor coefficient that we are evaluating.
558During calls to $cref atomic_afun$$, $icode%p% == 0%$$.
559
560$head vx$$
561The $code forward$$ argument $icode vx$$ has prototype
562$codei%
563        const CppAD::vector<bool>& %vx%
564%$$
565The case $icode%vx%.size() > 0%$$ only occurs while evaluating a call to
566$cref atomic_afun$$.
567In this case,
568$icode%q% == %p% == 0%$$,
569$icode%vx%.size() == %n%$$, and
570for $latex j = 0 , \ldots , n-1$$,
571$icode%vx%[%j%]%$$ is true if and only if
572$icode%ax%[%j%]%$$ is a $cref/variable/glossary/Variable/$$
573in the corresponding call to
574$codei%
575        %afun%(%ax%, %ay%, %id%)
576%$$
577If $icode%vx%.size() == 0%$$,
578then $icode%vy%.size() == 0%$$ and neither of these vectors
579should be used.
580
581$head vy$$
582The $code forward$$ argument $icode vy$$ has prototype
583$codei%
584        CppAD::vector<bool>& %vy%
585%$$
586If $icode%vy%.size() == 0%$$, it should not be used.
587Otherwise,
588$icode%p% == 0%$$ and $icode%vy%.size() == %m%$$.
589The input values of the elements of $icode vy$$
590are not specified (must not matter).
591Upon return, for $latex j = 0 , \ldots , m-1$$,
592$icode%vy%[%i%]%$$ is true if and only if
593$icode%ay%[%i%]%$$ is a variable
594(CppAD uses $icode vy$$ to reduce the necessary computations).
595
596$head tx$$
597The argument $icode tx$$ has prototype
598$codei%
599        const CppAD::vector<%Base%>& %tx%
600%$$
601and $icode%tx%.size() == (%p%+1)*%n%$$.
602For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , p$$,
603we use the Taylor coefficient notation
604$latex \[
605\begin{array}{rcl}
606        x_j^k    & = & tx [ j * ( p + 1 ) + k ]
607        \\
608        X_j (t)  & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^p t^p
609\end{array}
610\] $$
611Note that superscripts represent an index for $latex x_j^k$$
612and an exponent for $latex t^k$$.
613Also note that the Taylor coefficients for $latex X(t)$$ correspond
614to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way:
615$latex \[
616        x_j^k = \frac{1}{ k ! } X_j^{(k)} (0)
617\] $$
618
619$head ty$$
620The argument $icode ty$$ has prototype
621$codei%
622        CppAD::vector<%Base%>& %ty%
623%$$
624and $icode%tx%.size() == (%p%+1)*%m%$$.
625Upon return,
626For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , p$$,
627$latex \[
628\begin{array}{rcl}
629        Y_i (t)  & = & f_i [ X(t) ]
630        \\
631        Y_i (t)  & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^p t^p + o ( t^p )
632        \\
633        ty [ i * ( p + 1 ) + k ] & = & y_i^k
634\end{array}
635\] $$
636where $latex o( t^p ) / t^p \rightarrow 0$$ as $latex t \rightarrow 0$$.
637Note that superscripts represent an index for $latex y_j^k$$
638and an exponent for $latex t^k$$.
639Also note that the Taylor coefficients for $latex Y(t)$$ correspond
640to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way:
641$latex \[
642        y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0)
643\] $$
644If $latex q > 0$$,
645for $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , q-1$$,
646the input of $icode ty$$ satisfies
647$latex \[
648        ty [ i * ( p + 1 ) + k ] = y_i^k
649\]$$
650and hence the corresponding elements need not be recalculated.
651
652$head ok$$
653If the required results are calculated, $icode ok$$ should be true.
654Otherwise, it should be false.
655
656$head Discussion$$
657For example, suppose that $icode%p% == 2%$$,
658and you know how to compute the function $latex f(x)$$,
659its first derivative $latex f^{(1)} (x)$$,
660and it component wise Hessian $latex f_i^{(2)} (x)$$.
661Then you can compute $icode ty$$ using the following formulas:
662$latex \[
663\begin{array}{rcl}
664y_i^0 & = & Y(0)
665        = f_i ( x^0 )
666\\
667y_i^1 & = & Y^{(1)} ( 0 )
668        = f_i^{(1)} ( x^0 ) X^{(1)} ( 0 )
669        = f_i^{(1)} ( x^0 ) x^1
670\\
671y_i^2
672& = & \frac{1}{2 !} Y^{(2)} (0)
673\\
674& = & \frac{1}{2} X^{(1)} (0)^\R{T} f_i^{(2)} ( x^0 ) X^{(1)} ( 0 )
675  +   \frac{1}{2} f_i^{(1)} ( x^0 ) X^{(2)} ( 0 )
676\\
677& = & \frac{1}{2} (x^1)^\R{T} f_i^{(2)} ( x^0 ) x^1
678  +    f_i^{(1)} ( x^0 ) x^2
679\end{array}
680\] $$
681For $latex i = 0 , \ldots , m-1$$, and $latex k = 0 , 1 , 2$$,
682$latex \[
683        ty [ i * (p + 1) + k ] = y_i^k
684\] $$
685
686$head Examples$$
687The following files contain example atomic $code forward$$ functions:
688$cref%get_started.cpp%atomic_get_started.cpp%forward%$$,
689$cref%reciprocal.cpp%atomic_reciprocal.cpp%forward%$$,
690$cref%tangent.cpp%atomic_tangent.cpp%forward%$$,
691$cref%matrix_mul.hpp%atomic_matrix_mul.hpp%forward%$$.
692
693 
694$end
695-----------------------------------------------------------------------------
696*/
697/*!
698Link from atomic_base to forward mode
699
700\param q [in]
701lowerest order for this forward mode calculation.
702
703\param p [in]
704highest order for this forward mode calculation.
705
706\param vx [in]
707if size not zero, which components of \c x are variables
708
709\param vy [out]
710if size not zero, which components of \c y are variables
711
712\param tx [in]
713Taylor coefficients corresponding to \c x for this calculation.
714
715\param ty [out]
716Taylor coefficient corresponding to \c y for this calculation
717
718See the forward mode in user's documentation for base_atomic
719*/
720virtual bool forward(
721        size_t                    q  ,
722        size_t                    p  ,
723        const vector<bool>&       vx ,
724              vector<bool>&       vy ,
725        const vector<Base>&       tx ,
726              vector<Base>&       ty )
727{       return false; }
728/*
729-----------------------------------------------------------------------------
730$begin atomic_reverse$$
731$spell
732        mul.hpp
733        afun
734        ty
735        px
736        py
737        Taylor
738        const
739        CppAD
740$$
741
742$section Atomic Reverse Mode$$
743$index atomic, reverse callback$$
744$index reverse, atomic callback$$
745$index reverse, atomic virtual$$
746$spell
747        bool
748$$
749
750$head Syntax$$
751$icode%ok% = %afun%.reverse(%p%, %tx%, %ty%, %px%, %py%)%$$
752
753$head Purpose$$
754This function is used by $cref/reverse/Reverse/$$
755to compute derivatives.
756
757$head Implementation$$
758If you are using
759$cref/reverse/Reverse/$$ mode,
760this virtual function must be defined by the
761$cref/atomic_user/atomic_ctor/atomic_user/$$ class.
762It can just return $icode%ok% == false%$$
763(and not compute anything) for values
764of $icode p$$ that are greater than those used by your
765$cref/reverse/Reverse/$$ mode calculations.
766
767$head p$$
768The argument $icode p$$ has prototype
769$codei%
770        size_t %p%
771%$$
772It specifies the highest order Taylor coefficient that
773computing the derivative of.
774
775$head tx$$
776The argument $icode tx$$ has prototype
777$codei%
778        const CppAD::vector<%Base%>& %tx%
779%$$
780and $icode%tx%.size() == (%p%+1)*%n%$$.
781For $latex j = 0 , \ldots , n-1$$ and $latex k = 0 , \ldots , p$$,
782we use the Taylor coefficient notation
783$latex \[
784\begin{array}{rcl}
785        x_j^k    & = & tx [ j * ( p + 1 ) + k ]
786        \\
787        X_j (t)  & = & x_j^0 + x_j^1 t^1 + \cdots + x_j^p t^p
788\end{array}
789\] $$
790Note that superscripts represent an index for $latex x_j^k$$
791and an exponent for $latex t^k$$.
792Also note that the Taylor coefficients for $latex X(t)$$ correspond
793to the derivatives of $latex X(t)$$ at $latex t = 0$$ in the following way:
794$latex \[
795        x_j^k = \frac{1}{ k ! } X_j^{(k)} (0)
796\] $$
797
798$head ty$$
799The argument $icode ty$$ has prototype
800$codei%
801        const CppAD::vector<%Base%>& %ty%
802%$$
803and $icode%tx%.size() == (%p%+1)*%m%$$.
804For $latex i = 0 , \ldots , m-1$$ and $latex k = 0 , \ldots , p$$,
805we use the Taylor coefficient notation
806$latex \[
807\begin{array}{rcl}
808        Y_i (t)  & = & f_i [ X(t) ]
809        \\
810        Y_i (t)  & = & y_i^0 + y_i^1 t^1 + \cdots + y_i^p t^p + o ( t^p )
811        \\
812        y_i^k    & = & ty [ i * ( p + 1 ) + k ]
813\end{array}
814\] $$
815where $latex o( t^p ) / t^p \rightarrow 0$$ as $latex t \rightarrow 0$$.
816Note that superscripts represent an index for $latex y_j^k$$
817and an exponent for $latex t^k$$.
818Also note that the Taylor coefficients for $latex Y(t)$$ correspond
819to the derivatives of $latex Y(t)$$ at $latex t = 0$$ in the following way:
820$latex \[
821        y_j^k = \frac{1}{ k ! } Y_j^{(k)} (0)
822\] $$
823
824
825$head F, G, H$$
826We use the notation $latex \{ x_j^k \} \in B^{n \times (p+1)}$$ for
827$latex \[
828        \{ x_j^k \W{:} j = 0 , \ldots , n-1, k = 0 , \ldots , p \}
829\]$$
830We use the notation $latex \{ y_i^k \} \in B^{m \times (p+1)}$$ for
831$latex \[
832        \{ y_i^k \W{:} i = 0 , \ldots , m-1, k = 0 , \ldots , p \}
833\]$$
834We define the function
835$latex F : B^{n \times (p+1)} \rightarrow B^{m \times (p+1)}$$ by
836$latex \[
837        y_i^k = F_i^k [ \{ x_j^k \} ]
838\] $$
839We use $latex G : B^{m \times (p+1)} \rightarrow B$$
840to denote an arbitrary scalar valued function of $latex \{ y_i^k \}$$.
841We use $latex H : B^{n \times (p+1)} \rightarrow B$$
842defined by
843$latex \[
844        H ( \{ x_j^k \} ) = G[ F( \{ x_j^k \} ) ]
845\] $$
846
847$head py$$
848The argument $icode py$$ has prototype
849$codei%
850        const CppAD::vector<%Base%>& %py%
851%$$
852and $icode%py%.size() == m * (%p%+1)%$$.
853For $latex i = 0 , \ldots , m-1$$, $latex k = 0 , \ldots , p$$,
854$latex \[
855        py[ i * (p + 1 ) + k ] = \partial G / \partial y_i^k
856\] $$
857
858$subhead px$$
859The $icode px$$ has prototype
860$codei%
861        CppAD::vector<%Base%>& %px%
862%$$
863and $icode%px%.size() == n * (%p%+1)%$$.
864The input values of the elements of $icode px$$
865are not specified (must not matter).
866Upon return,
867for $latex j = 0 , \ldots , n-1$$ and $latex \ell = 0 , \ldots , p$$,
868$latex \[
869\begin{array}{rcl}
870px [ j * (p + 1) + \ell ] & = & \partial H / \partial x_j^\ell
871\\
872& = &
873( \partial G / \partial \{ y_i^k \} )
874        ( \partial \{ y_i^k \} / \partial x_j^\ell )
875\\
876& = &
877\sum_{i=0}^{m-1} \sum_{k=0}^p
878( \partial G / \partial y_i^k ) ( \partial y_i^k / \partial x_j^\ell )
879\\
880& = &
881\sum_{i=0}^{m-1} \sum_{k=\ell}^p
882py[ i * (p + 1 ) + k ] ( \partial F_i^k / \partial x_j^\ell )
883\end{array}
884\] $$
885Note that we have used the fact that for $latex k < \ell$$,
886$latex \partial F_i^k / \partial x_j^\ell = 0$$.
887
888$head ok$$
889The return value $icode ok$$ has prototype
890$codei%
891        bool %ok%
892%$$
893If it is $code true$$, the corresponding evaluation succeeded,
894otherwise it failed.
895
896$head Examples$$
897The following files contain example atomic $code reverse$$ functions:
898$cref%reciprocal.cpp%atomic_reciprocal.cpp%reverse%$$,
899$cref%tangent.cpp%atomic_tangent.cpp%reverse%$$,
900$cref%matrix_mul.hpp%atomic_matrix_mul.hpp%reverse%$$.
901
902
903$end
904-----------------------------------------------------------------------------
905*/
906/*!
907Link from reverse mode sweep to users routine.
908
909\param p [in]
910highest order for this reverse mode calculation.
911
912\param tx [in]
913Taylor coefficients corresponding to \c x for this calculation.
914
915\param ty [in]
916Taylor coefficient corresponding to \c y for this calculation
917
918\param px [out]
919Partials w.r.t. the \c x Taylor coefficients.
920
921\param py [in]
922Partials w.r.t. the \c y Taylor coefficients.
923
924See atomic_reverse mode use documentation
925*/
926virtual bool reverse(
927        size_t                    p  ,
928        const vector<Base>&       tx ,
929        const vector<Base>&       ty ,
930              vector<Base>&       px ,
931        const vector<Base>&       py )
932{       return false; }
933/*
934-------------------------------------- ---------------------------------------
935$begin atomic_for_sparse_jac$$
936$spell
937        mul.hpp
938        afun
939        Jacobian
940        jac
941        const
942        CppAD
943        std
944        bool
945        std
946$$
947
948$section Atomic Forward Jacobian Sparsity Patterns$$
949$index atomic, for_sparse_jac callback$$
950$index for_sparse_jac, atomic callback$$
951$index for_sparse_jac, atomic virtual$$
952
953$head Syntax$$
954$icode%ok% = %afun%.for_sparse_jac(%q%, %r%, %s%)%$$
955
956$head Purpose$$
957This function is used by $cref ForSparseJac$$ to compute
958Jacobian sparsity patterns.
959For a fixed matrix $latex R \in B^{n \times q}$$,
960the Jacobian of $latex f( x + R * u)$$ with respect to $latex u \in B^q$$ is
961$latex \[
962        S(x) = f^{(1)} (x) * R
963\] $$
964Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$,
965$code for_sparse_jac$$ computes a sparsity pattern for $latex S(x)$$.
966
967$head Implementation$$
968If you are using $cref ForSparseJac$$,
969this virtual function must be defined by the
970$cref/atomic_user/atomic_ctor/atomic_user/$$ class.
971
972$subhead q$$
973The argument $icode q$$ has prototype
974$codei%
975     size_t %q%
976%$$
977It specifies the number of columns in
978$latex R \in B^{n \times q}$$ and the Jacobian
979$latex S(x) \in B^{m \times q}$$.
980
981$subhead r$$
982This argument has prototype
983$codei%
984     const %atomic_sparsity%& %r%
985%$$
986and is a $cref/atomic_sparsity/atomic_option/atomic_sparsity/$$ pattern for
987$latex R \in B^{n \times q}$$.
988
989$subhead s$$
990This argument has prototype
991$codei%
992        %atomic_sparsity%& %s%
993%$$
994The input values of its elements
995are not specified (must not matter).
996Upon return, $icode s$$ is a
997$cref/atomic_sparsity/atomic_option/atomic_sparsity/$$ pattern for
998$latex S(x) \in B^{m \times q}$$.
999
1000$head ok$$
1001The return value $icode ok$$ has prototype
1002$codei%
1003        bool %ok%
1004%$$
1005If it is $code true$$, the corresponding evaluation succeeded,
1006otherwise it failed.
1007
1008$head Examples$$
1009The following files contain example atomic $code for_sparse_jac$$ functions:
1010$cref%reciprocal.cpp%atomic_reciprocal.cpp%for_sparse_jac%$$,
1011$cref%tangent.cpp%atomic_tangent.cpp%for_sparse_jac%$$,
1012$cref%matrix_mul.hpp%atomic_matrix_mul.hpp%for_sparse_jac%$$.
1013
1014$end
1015-----------------------------------------------------------------------------
1016*/
1017/*!
1018Link from forward Jacobian sparsity sweep to atomic_base
1019
1020\param q
1021is the column dimension for the Jacobian sparsity partterns.
1022
1023\param r
1024is the Jacobian sparsity pattern for the argument vector x
1025
1026\param s
1027is the Jacobian sparsity pattern for the result vector y
1028*/
1029virtual bool for_sparse_jac(
1030        size_t                                  q  ,
1031        const vector< std::set<size_t> >&       r  ,
1032              vector< std::set<size_t> >&       s  )
1033{       return false; }
1034virtual bool for_sparse_jac(
1035        size_t                                  q  ,
1036        const vector<bool>&                     r  ,
1037              vector<bool>&                     s  )
1038{       return false; }
1039/*
1040-------------------------------------- ---------------------------------------
1041$begin atomic_rev_sparse_jac$$
1042$spell
1043        mul.hpp
1044        rt
1045        afun
1046        Jacobian
1047        jac
1048        CppAD
1049        std
1050        bool
1051        const
1052        hes
1053$$
1054
1055$section Atomic Reverse Jacobian Sparsity Patterns$$
1056$index atomic, rev_sparse_jac callback$$
1057$index rev_sparse_jac, atomic callback$$
1058$index rev_sparse_jac, atomic virtual$$
1059
1060$head Syntax$$
1061$icode%ok% = %afun%.rev_sparse_jac(%q%, %rt%, %st%)%$$
1062
1063$head Purpose$$
1064This function is used by $cref RevSparseJac$$ to compute
1065Jacobian sparsity patterns.
1066For a fixed matrix $latex R \in B^{q \times m}$$,
1067the Jacobian of $latex R * f( x )$$ with respect to $latex x \in B^q$$ is
1068$latex \[
1069        S(x) = R * f^{(1)} (x)
1070\] $$
1071Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for $latex R$$,
1072$code rev_sparse_jac$$ computes a sparsity pattern for $latex S(x)$$.
1073
1074$head Implementation$$
1075If you are using $cref RevSparseJac$$,
1076this virtual function must be defined by the
1077$cref/atomic_user/atomic_ctor/atomic_user/$$ class.
1078
1079$subhead q$$
1080The argument $icode q$$ has prototype
1081$codei%
1082     size_t %q%
1083%$$
1084It specifies the number of rows in
1085$latex R \in B^{q \times m}$$ and the Jacobian
1086$latex S(x) \in B^{q \times n}$$.
1087
1088$subhead rt$$
1089This argument has prototype
1090$codei%
1091     const %atomic_sparsity%& %rt%
1092%$$
1093and is a
1094$cref/atomic_sparsity/atomic_option/atomic_sparsity/$$ pattern for
1095$latex R^\R{T} \in B^{m \times q}$$.
1096
1097$subhead st$$
1098This argument has prototype
1099$codei%
1100        %atomic_sparsity%& %st%
1101%$$
1102The input value of its elements
1103are not specified (must not matter).
1104Upon return, $icode s$$ is a
1105$cref/atomic_sparsity/atomic_option/atomic_sparsity/$$ pattern for
1106$latex S(x)^\R{T} \in B^{n \times q}$$.
1107
1108$head ok$$
1109The return value $icode ok$$ has prototype
1110$codei%
1111        bool %ok%
1112%$$
1113If it is $code true$$, the corresponding evaluation succeeded,
1114otherwise it failed.
1115
1116$head Examples$$
1117The following files contain example atomic $code rev_sparse_jac$$ functions:
1118$cref%reciprocal.cpp%atomic_reciprocal.cpp%rev_sparse_jac%$$,
1119$cref%tangent.cpp%atomic_tangent.cpp%rev_sparse_jac%$$,
1120$cref%matrix_mul.hpp%atomic_matrix_mul.hpp%rev_sparse_jac%$$.
1121
1122$end
1123-----------------------------------------------------------------------------
1124*/
1125/*!
1126Link from reverse Jacobian sparsity sweep to atomic_base
1127
1128\param q [in]
1129is the row dimension for the Jacobian sparsity partterns
1130
1131\param rt [out]
1132is the tansposed Jacobian sparsity pattern w.r.t to range variables y
1133
1134\param st [in]
1135is the tansposed Jacobian sparsity pattern for the argument variables x
1136*/
1137virtual bool rev_sparse_jac(
1138        size_t                                  q  ,
1139        const vector< std::set<size_t> >&       rt ,
1140              vector< std::set<size_t> >&       st )
1141{       return false; }
1142virtual bool rev_sparse_jac(
1143        size_t                                  q  ,
1144        const vector<bool>&                     rt ,
1145              vector<bool>&                     st )
1146{       return false; }
1147/*
1148-------------------------------------- ---------------------------------------
1149$begin atomic_rev_sparse_hes$$
1150$spell
1151        mul.hpp
1152        vx
1153        afun
1154        Jacobian
1155        jac
1156        CppAD
1157        std
1158        bool
1159        hes
1160        const
1161$$
1162
1163$section Atomic Reverse Hessian Sparsity Patterns$$
1164$index atomic, rev_sparse_hes callback$$
1165$index rev_sparse_hes, atomic callback$$
1166$index rev_sparse_hes, atomic virtual$$
1167
1168$head Syntax$$
1169$icode%ok% = %afun%.rev_sparse_hes(%vx%, %s%, %t%, %q%, %r%, %u%, %v%)%$$
1170
1171$head Purpose$$
1172This function is used by $cref RevSparseHes$$ to compute
1173Hessian sparsity patterns.
1174There is an unspecified scalar valued function
1175$latex g : B^m \rightarrow B$$.
1176Given a $cref/sparsity pattern/glossary/Sparsity Pattern/$$ for
1177$latex R \in B^{n \times q}$$,
1178and information about the function $latex z = g(y)$$,
1179this routine computes the sparsity pattern for
1180$latex \[
1181        V(x) = (g \circ f)^{(2)}( x ) R
1182\] $$
1183
1184$head Implementation$$
1185If you are using and $cref RevSparseHes$$,
1186this virtual function must be defined by the
1187$cref/atomic_user/atomic_ctor/atomic_user/$$ class.
1188
1189$subhead vx$$
1190The argument $icode vx$$ has prototype
1191$codei%
1192     const CppAD:vector<bool>& %vx%
1193%$$
1194$icode%vx%.size() == %n%$$, and
1195for $latex j = 0 , \ldots , n-1$$,
1196$icode%vx%[%j%]%$$ is true if and only if
1197$icode%ax%[%j%]%$$ is a $cref/variable/glossary/Variable/$$
1198in the corresponding call to
1199$codei%
1200        %afun%(%ax%, %ay%, %id%)
1201%$$
1202
1203$subhead s$$
1204The argument $icode s$$ has prototype
1205$codei%
1206     const CppAD:vector<bool>& %s%
1207%$$
1208and its size is $icode m$$.
1209It is a sparsity pattern for
1210$latex S(x) = g^{(1)} (y) \in B^{1 \times m}$$.
1211
1212$subhead t$$
1213This argument has prototype
1214$codei%
1215     CppAD:vector<bool>& %t%
1216%$$
1217and its size is $icode m$$.
1218The input values of its elements
1219are not specified (must not matter).
1220Upon return, $icode t$$ is a
1221sparsity pattern for
1222$latex T(x) \in B^{1 \times n}$$ where
1223$latex \[
1224        T(x) = (g \circ f)^{(1)} (x) = S(x) * f^{(1)} (x)
1225\]$$
1226
1227$subhead q$$
1228The argument $icode q$$ has prototype
1229$codei%
1230     size_t %q%
1231%$$
1232It specifies the number of columns in
1233$latex R \in B^{n \times q}$$,
1234$latex U(x) \in B^{m \times q}$$, and
1235$latex V(x) \in B^{n \times q}$$.
1236
1237$subhead r$$
1238This argument has prototype
1239$codei%
1240     const %atomic_sparsity%& %r%
1241%$$
1242and is a $cref/atomic_sparsity/atomic_option/atomic_sparsity/$$ pattern for
1243$latex R \in B^{n \times q}$$.
1244
1245$head u$$
1246This argument has prototype
1247$codei%
1248     const %atomic_sparsity%& %u%
1249%$$
1250and is a $cref/atomic_sparsity/atomic_option/atomic_sparsity/$$ pattern for
1251$latex U(x) \in B^{m \times q}$$ which is defined by
1252$latex \[
1253\begin{array}{rcl}
1254U(x)
1255& = &
1256\partial_u \{ \partial_y g[ y + f^{(1)} (x) R u ] \}_{u=0}
1257\\
1258& = &
1259\partial_u \{ g^{(1)} [ y + f^{(1)} (x) R u ] \}_{u=0}
1260\\
1261& = &
1262g^{(2)} (y) f^{(1)} (x) R
1263\end{array}
1264\] $$
1265
1266$subhead v$$
1267This argument has prototype
1268$codei%
1269     %atomic_sparsity%& %v%
1270%$$
1271The input value of its elements
1272are not specified (must not matter).
1273Upon return, $icode v$$ is a
1274$cref/atomic_sparsity/atomic_option/atomic_sparsity/$$ pattern for
1275$latex V(x) \in B^{n \times q}$$ which is defined by
1276$latex \[
1277\begin{array}{rcl}
1278V(x)
1279& = &
1280\partial_u [ \partial_x (g \circ f) ( x + R u )  ]_{u=0}
1281\\
1282& = &
1283\partial_u [ (g \circ f)^{(1)}( x + R u )  ]_{u=0}
1284\\
1285& = &
1286(g \circ f)^{(2)}( x ) R
1287\\
1288& = &
1289f^{(1)} (x)^\R{T} g^{(2)} ( y ) f^{(1)} (x)  R
1290+
1291\sum_{i=1}^m g_i^{(1)} (y) \; f_i^{(2)} (x) R
1292\\
1293& = &
1294f^{(1)} (x)^\R{T} U(x)
1295+
1296\sum_{i=1}^m S_i (x) \; f_i^{(2)} (x) R
1297\end{array}
1298\] $$
1299
1300$head Examples$$
1301The following files contain example atomic $code rev_sparse_hes$$ functions:
1302$cref%reciprocal.cpp%atomic_reciprocal.cpp%rev_sparse_hes%$$,
1303$cref%tangent.cpp%atomic_tangent.cpp%rev_sparse_hes%$$,
1304$cref%matrix_mul.hpp%atomic_matrix_mul.hpp%rev_sparse_hes%$$.
1305
1306$end
1307-----------------------------------------------------------------------------
1308*/
1309/*!
1310Link from reverse Hessian sparsity sweep to base_atomic
1311
1312\param vx [in]
1313which componens of x are variables.
1314
1315\param s [in]
1316is the reverse Jacobian sparsity pattern w.r.t the result vector y.
1317
1318\param t [out]
1319is the reverse Jacobian sparsity pattern w.r.t the argument vector x.
1320
1321\param q [in]
1322is the column dimension for the sparsity partterns.
1323
1324\param r [in]
1325is the forward Jacobian sparsity pattern w.r.t the argument vector x
1326
1327\param u [in]
1328is the Hessian sparsity pattern w.r.t the result vector y.
1329
1330\param v [out]
1331is the Hessian sparsity pattern w.r.t the argument vector x.
1332*/
1333virtual bool rev_sparse_hes(
1334        const vector<bool>&                     vx ,
1335        const vector<bool>&                     s  ,
1336              vector<bool>&                     t  ,
1337        size_t                                  q  ,
1338        const vector< std::set<size_t> >&       r  ,
1339        const vector< std::set<size_t> >&       u  ,
1340              vector< std::set<size_t> >&       v  )
1341{       return false; }
1342virtual bool rev_sparse_hes(
1343        const vector<bool>&                     vx ,
1344        const vector<bool>&                     s  ,
1345              vector<bool>&                     t  ,
1346        size_t                                  q  ,
1347        const vector<bool>&                     r  ,
1348        const vector<bool>&                     u  ,
1349              vector<bool>&                     v  )
1350{       return false; }
1351/*
1352------------------------------------------------------------------------------
1353$begin atomic_base_clear$$
1354
1355$section Free Static Variables$$
1356$index free, atomic static$$
1357$index atomic, free static$$
1358$index static, free atomic$$
1359$index clear, atomic static$$
1360
1361$head Syntax$$
1362$codei%atomic_base<%Base%>::clear()%$$
1363
1364$head Purpose$$
1365The $code atomic_base$$ class holds onto static work space in order to
1366increase speed by avoiding system memory allocation calls.
1367This call makes to work space $cref/available/ta_available/$$ to
1368for other uses by the same thread.
1369This should be called when you are done using the
1370user atomic functions for a specific value of $icode Base$$.
1371
1372$head Restriction$$
1373This routine cannot be called
1374while in $cref/parallel/ta_in_parallel/$$ execution mode.
1375
1376$end
1377------------------------------------------------------------------------------
1378*/
1379/*!
1380Free all thread_alloc static memory held by atomic_base (avoids reallocations).
1381(This does not include class_object() which is an std::vector.)
1382*/
1383/// Free vector memory used by this class (work space)
1384static void clear(void)
1385{       CPPAD_ASSERT_KNOWN(
1386                ! thread_alloc::in_parallel() ,
1387                "cannot use atomic_base clear during parallel execution"
1388        );
1389        size_t i = class_object().size();
1390        while(i--)
1391        {       size_t thread = CPPAD_MAX_NUM_THREADS;
1392                while(thread--)
1393                {
1394                        atomic_base* op = class_object()[i];
1395                        if( op != CPPAD_NULL )
1396                        {       op->afun_vx_[thread].clear();
1397                                op->afun_vy_[thread].clear();
1398                                op->afun_tx_[thread].clear();
1399                                op->afun_ty_[thread].clear();
1400                        }
1401                }
1402        }
1403        return;
1404}
1405// -------------------------------------------------------------------------
1406/*!
1407Set value of id (used by deprecated old_atomic class)
1408
1409This function is called just before calling any of the virtual funcitons
1410and has the corresponding id of the corresponding virtual call.
1411*/
1412virtual void set_id(size_t id) 
1413{ }
1414// ---------------------------------------------------------------------------
1415};
1416/*! \} */
1417CPPAD_END_NAMESPACE
1418# endif
Note: See TracBrowser for help on using the repository browser.