source: trunk/test_more/optimize.cpp @ 3008

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

Use atomic option setting to select bool or set sparsity during optimize.

atomic_base.hpp: fix sparsity option documentation.

  • Property svn:keywords set to Id
File size: 36.9 KB
Line 
1/* $Id: optimize.cpp 3008 2013-11-13 14:59:21Z bradbell $ */
2/* --------------------------------------------------------------------------
3CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-13 Bradley M. Bell
4
5CppAD is distributed under multiple licenses. This distribution is under
6the terms of the
7                    Eclipse Public License Version 1.0.
8
9A copy of this license is included in the COPYING file of this distribution.
10Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
11-------------------------------------------------------------------------- */
12// 2DO: Test that optimize.hpp use of base_atomic<Base>::rev_sparse_jac works.
13
14# include <limits>
15# include <cppad/cppad.hpp>
16
17
18namespace {
19        // note this enum type is not part of the API (but its values are)
20        CppAD::atomic_base<double>::option_enum atomic_sparsity_option;
21        //
22        // ----------------------------------------------------------------
23        // Test nested conditional expressions.
24        int nested_cond_exp(void)
25        {       bool ok = true;
26                using CppAD::AD;
27                using CppAD::vector;
28       
29                // independent variable vector
30                vector< AD<double> > ax(2), ay(1);
31                ax[0] = 1.0;
32                ax[1] = 2.0;
33                Independent(ax);
34       
35                // first conditional expression
36                AD<double> ac1 = CondExpLe(ax[0], ax[1], 2.0 * ax[0], 3.0 * ax[1] );
37       
38                // second conditional expression
39                AD<double> ac2 = CondExpGe(ax[0], ax[1], 4.0 * ax[0], 5.0 * ax[1] );
40       
41                // third conditional expression
42                AD<double> ac3 = CondExpLt(ax[0], ax[1], 6.0 * ac1, 7.0 * ac2 );
43       
44                // create function object f : ax -> ay
45                ay[0] = ac3;
46                CppAD::ADFun<double> f(ax, ay);
47       
48                // now optimize the operation sequence
49                f.optimize();
50       
51                // now zero order forward
52                vector<double> x(2), y(1);
53                for(size_t i = 0; i < 3; i++)
54                {       x[0] = 1.0 - double(i);
55                        x[1] = - x[0];
56                        y    = f.Forward(0, x);
57                        //
58                        // first conditional expression
59                        double c1;
60                        if( x[0] <= x[1] )
61                                c1 = 2.0 * x[0];
62                        else    c1 = 3.0 * x[1];
63                        //
64                        // second conditional expression
65                        double c2;
66                        if( x[0] >= x[1] )
67                                c2 = 4.0 * x[0];
68                        else    c2 = 5.0 * x[1];
69       
70                        // third conditional expression
71                        double c3;
72                        if( x[0] < x[1] )
73                                c3 = 6.0 * c1;
74                        else    c3 = 7.0 * c2;
75       
76                        ok &= y[0] == c3;
77                }
78                return ok;
79        }
80        // ----------------------------------------------------------------
81        // Test for bug where checkpoint function did not depend on
82        // the operands in the logical comparison because of the CondExp
83        // sparsity pattern.
84        void j_algo( 
85                const CppAD::vector< CppAD::AD<double> >& ax ,
86                      CppAD::vector< CppAD::AD<double> >& ay )
87        {       ay[0] = CondExpGt(ax[0], ax[1], ax[2], ax[3]); }
88       
89        bool atomic_cond_exp_sparsity(void)
90        {       bool ok = true;
91                using CppAD::AD;
92                using CppAD::vector;
93       
94                // Create a checkpoint version of the function g
95                vector< AD<double> > au(4), av(1);
96                for(size_t i = 0; i < 4; i++)
97                        au[i] = AD<double>(i);
98                CppAD::checkpoint<double> j_check("j_check", j_algo, au, av);
99       
100                // independent variable vector
101                vector< AD<double> > ax(2), ay(1);
102                ax[0] = 1.;
103                ax[1] = 1.;
104                Independent(ax);
105       
106                // call atomic function that does not get used
107                for(size_t i = 0; i < 4; i++) 
108                        au[i] = ax[0] + AD<double>(i + 1) * ax[1];
109                j_check(au, ay);
110       
111                // create function object f : ax -> ay
112                CppAD::ADFun<double> f(ax, ay);
113
114       
115                // now optimize the operation sequence
116                j_check.option( atomic_sparsity_option );
117                f.optimize();
118       
119                // check result where true case is used; i.e., au[0] > au[1]
120                vector<double> x(2), y(1);
121                x[0] = 1.;
122                x[1] = -1;
123                y    = f.Forward(0, x);
124                ok  &= y[0] == x[0] + double(3) * x[1];
125               
126       
127                // check result where false case is used; i.e., au[0] <= au[1]
128                x[0] = 1.;
129                x[1] = 1;
130                y    = f.Forward(0, x);
131                ok  &= y[0] == x[0] + double(4) * x[1];
132               
133                return ok;
134        }
135        // -------------------------------------------------------------------
136        // Test conditional optimizing out call to an atomic function call
137        void k_algo(
138                const CppAD::vector< CppAD::AD<double> >& x ,
139                      CppAD::vector< CppAD::AD<double> >& y )
140        {       y[0] = x[0] + x[1]; }
141
142        void h_algo(
143                const CppAD::vector< CppAD::AD<double> >& x ,
144                      CppAD::vector< CppAD::AD<double> >& y )
145        {       y[0] = x[0] - x[1]; }
146
147        bool atomic_cond_exp(void)
148        {       bool ok = true;
149                typedef CppAD::vector< CppAD::AD<double> > ADVector;
150
151                // Create a checkpoint version of the function g
152                ADVector ax(2), ag(1), ah(1), ay(1);
153                ax[0] = 0.;
154                ax[1] = 1.;
155                CppAD::checkpoint<double> k_check("k_check", k_algo, ax, ag);
156                CppAD::checkpoint<double> h_check("h_check", h_algo, ax, ah);
157
158                // independent variable vector
159                Independent(ax);
160
161                // atomic function calls that get conditionally used
162                k_check(ax, ag);
163                h_check(ax, ah);
164
165                // conditional expression
166                ay[0] = CondExpLt(ax[0], ax[1], ag[0], ah[0]); 
167       
168                // create function object f : ax -> ay
169                CppAD::ADFun<double> f;
170                f.Dependent(ax, ay);
171       
172                // use zero order to evaluate when condition is true
173                CppAD::vector<double>  x(2), dx(2);
174                CppAD::vector<double>  y(1), dy(1), w(1);
175                x[0] = 3.;
176                x[1] = 4.;
177                y    = f.Forward(0, x);
178                ok  &= y[0] == x[0] + x[1];
179
180                // before optimize
181                k_check.option( atomic_sparsity_option );
182                h_check.option( atomic_sparsity_option );
183                ok  &= f.number_skip() == 0;
184
185                // now optimize the operation sequence
186                f.optimize();
187
188                // optimized zero order forward when condition is false
189                x[0] = 4.;
190                x[1] = 3.;
191                y    = f.Forward(0, x);
192                ok  &= y[0] == x[0] - x[1];
193
194                // after optimize can skip either call to g or call to h
195                ok  &= f.number_skip() == 1;
196
197                // optimized first order forward
198                dx[0] = 2.;
199                dx[1] = 1.;
200                dy    = f.Forward(1, dx);
201                ok   &= dy[0] == dx[0] - dx[1];
202
203                // optimized first order reverse
204                w[0]  = 1.;
205                dx    = f.Reverse(1, w);
206                ok   &= dx[0] == 1.;
207                ok   &= dx[1] == -1.;
208       
209                return ok;
210        }
211        // -------------------------------------------------------------------
212        // Test of optimizing out arguments to an atomic function
213        void g_algo( 
214                const CppAD::vector< CppAD::AD<double> >& ax ,
215                      CppAD::vector< CppAD::AD<double> >& ay )
216        {       ay = ax; }
217
218        bool atomic_no_used(void)
219        {       bool ok = true;
220                using CppAD::AD;
221                using CppAD::vector;
222       
223                // Create a checkpoint version of the function g
224                vector< AD<double> > ax(2), ay(2), az(1);
225                ax[0] = 0.;
226                ax[1] = 1.;
227                CppAD::checkpoint<double> g_check("g_check", g_algo, ax, ay);
228       
229                // independent variable vector
230                Independent(ax);
231       
232                // call atomic function that does not get used
233                g_check(ax, ay);
234       
235                // conditional expression
236                az[0] = CondExpLt(ax[0], ax[1], ax[0] + ax[1], ax[0] - ax[1]); 
237               
238                // create function object f : ax -> az
239                CppAD::ADFun<double> f(ax, az);
240
241                // number of variables before optimization
242                // (include ay[0] and ay[1])
243                size_t n_before = f.size_var();
244               
245                // now optimize the operation sequence
246                g_check.option( atomic_sparsity_option );
247                f.optimize();
248
249                // number of variables after optimization
250                // (does not include ay[0] and ay[1])
251                size_t n_after = f.size_var();
252                ok            &= n_after + 2 == n_before;
253       
254                // check optimization works ok
255                vector<double> x(2), z(1);
256                x[0] = 4.;
257                x[1] = 3.;
258                z    = f.Forward(0, x);
259                ok  &= z[0] == x[0] - x[1];
260               
261                return ok;
262        }
263        bool atomic_arguments(void)
264        {       bool ok = true;
265                using CppAD::AD;
266                using CppAD::vector;
267                vector< AD<double> > au(2), aw(2), ax(2), ay(1);
268
269                // create atomic function corresponding to g_algo
270                au[0] = 1.0;
271                au[1] = 2.0;
272                CppAD::checkpoint<double> g_check("g_algo", g_algo, au, ax);
273
274                // start recording a new function
275                CppAD::Independent(ax);
276
277                // now use g_check during the recording
278                au[0] = ax[0] + ax[1]; // this argument requires a new variable
279                au[1] = ax[0] - ax[1]; // this argument also requires a new variable
280                g_check(au, aw);
281
282                // now create f(x) = x_0 - x_1
283                ay[0] = aw[0];
284                CppAD::ADFun<double> f(ax, ay);
285
286                // number of variables before optimization
287                size_t n_before = f.size_var();
288 
289                // now optimize f so that the calculation of au[1] is removed
290                g_check.option( atomic_sparsity_option );
291                f.optimize();
292
293                // check difference in number of variables
294                size_t n_after = f.size_var();
295                ok &= n_before == n_after + 1;
296
297                // now compute and check a forward mode calculation
298                vector<double> x(2), y(1);
299                x[0] = 5.0;
300                x[1] = 6.0;
301                y    = f.Forward(0, x);
302                ok  &= (y[0] == x[0] + x[1]); 
303
304                return ok;
305        }
306
307        // -------------------------------------------------------------------
308        // Test the reverse dependency analysis optimization
309        template <class Vector>
310        void depend_fun
311        (const Vector& x, Vector& y, size_t& original, size_t& opt)
312        {       typedef typename Vector::value_type Scalar;
313                Scalar a;
314                Scalar one(1), two(2), three(3), four(4);
315                original = 0;
316                opt      = 0;
317
318                // unary operator where operand is arg[0]
319                a = CppAD::abs(x[0]); 
320                if( a < 1. )
321                        y[0] = sin(x[0]);
322                else    y[0] = cos(x[0]); 
323                original += 3;
324                opt      += 2;
325
326                // binary operator where left operand is a variable
327                // and right operand is a parameter
328                a = x[1] + 2.;
329                if( a < 3. )
330                        y[1] = x[1] * 3.;
331                else    y[1] = x[1] / 2.;
332                original += 2;
333                opt      += 1;
334
335                // binary operator where left operand is a parameter
336                // and right operation is a variable
337                a = 2. - x[2];
338                if( a < 4. )
339                        y[2] = 3. / x[2];
340                else    y[2] = 4. + x[2];
341                original += 2;
342                opt      += 1;
343
344                // binary operator where both operands are variables
345                a = x[3] - x[2];
346                if( a < 4. )
347                        y[3] = x[3] / x[2];
348                else    y[3] = x[3] + x[2];
349                original += 2;
350                opt      += 1;
351
352                // this conditional expression that will be optimized out
353                a = CppAD::CondExpLt(x[0], x[1], x[2], x[3]);
354                // 1 of the following 2 conditional expressions will be kept
355                if( a < 5. )
356                        y[4] = CppAD::CondExpLt(x[4], one, two, three);
357                else    y[4] = CppAD::CondExpLt(x[4], two, three, four);
358                original += 2;
359                opt      += 1;
360
361                // Make sure that a parameter dependent variable
362                // is not optimized out of the operation sequence.
363                // In addition, we do not use the argument x[5], to
364                // make sure it is not optimized out.
365                y[5] = 1.;
366                original += 1;
367                opt      += 1;
368
369                return;
370        }
371
372        bool depend_one(void)
373        {       // Test all except for VecAD operations
374                bool ok = true;
375                using CppAD::AD;
376                size_t original;
377                size_t opt;
378                size_t i, j;
379       
380                // domain space vector
381                size_t n  = 6;
382                CppAD::vector< AD<double> > X(n);
383                for(j = 0; j < n; j++)
384                        X[j] = 1. / double(j + 1); 
385       
386                // declare independent variables and start tape recording
387                CppAD::Independent(X);
388       
389                // range space vector
390                size_t m = n;
391                CppAD::vector< AD<double> > Y(m);
392                depend_fun(X, Y, original, opt);
393       
394                // create f: X -> Y and stop tape recording
395                CppAD::ADFun<double> F;
396                F.Dependent(X, Y); 
397       
398                CppAD::vector<double> x(n), y(m), check(m);
399                for(j = 0; j < n; j++)
400                        x[j] = Value(X[j]);
401                y = F.Forward(0, x);
402                depend_fun(x, check, original, opt);
403                for(i = 0; i < m; i++)
404                        ok &= (y[i] == check[i]);
405       
406                // Check size before optimization
407                ok &= F.size_var() == (n + 1 + original);
408       
409                // Optimize the operation sequence
410                F.optimize();
411       
412                // Check size after optimization
413                ok &= F.size_var() == (n + 1 + opt);
414       
415                // check result now
416                // (should have already been checked if NDEBUG not defined)
417                y = F.Forward(0, x);
418                for(i = 0; i < m; i++)
419                        ok &= (y[i] == check[i]);
420       
421                return ok;
422        }
423
424        bool depend_two(void)
425        {       // Test VecAD operations
426                bool ok = true;
427                using CppAD::AD;
428                size_t i, j;
429
430                // domain space vector
431                size_t n  = 2;
432                CppAD::vector< AD<double> > X(n);
433                for(j = 0; j < n; j++)
434                        X[j] = double(j); 
435
436                // range space vector
437                size_t m = 3;
438                CppAD::vector< AD<double> > Y(m);
439
440                CppAD::VecAD<double> U(m);
441                CppAD::VecAD<double> V(n);
442                for(i = 0; i < m; i++)
443                        U[i] = 0;
444                for(j = 0; j < n; j++)
445                        V[j] = 0;
446       
447                // declare independent variables and start tape recording
448                CppAD::Independent(X);
449
450                // first vecad vector that is a variable
451                U[ X[0] ] = X[1];
452
453                // second vecad vector that is a variable
454                V[ X[0] ] = X[1];
455
456                // Make dependency for vecad vectors different that for
457                // variables because original code used worng dependency info.
458                // Y does not depend on the first variable in the tape; i.e.
459                // the one corresponding to the BeginOp. So make it depend
460                // on the first vecad vector in the tape.
461                for(i = 0; i < m; i++)
462                {       AD<double> I(i);
463                        Y[i] = U[I];
464                }
465       
466                // create f: X -> Y and stop tape recording
467                // Y[ X[0] ] = X[1] and other components of Y are zero.
468                CppAD::ADFun<double> F;
469                F.Dependent(X, Y); 
470
471                // Check number of VecAD vectors plus number of VecAD elements
472                ok &= (F.size_VecAD() == 2 + n + m); 
473       
474                CppAD::vector<double> x(n), y(m);
475                for(j = 0; j < n; j++)
476                        x[j] = double(j);
477
478                y = F.Forward(0, x);
479                for(i = 0; i < m; i++)
480                {       if( i != static_cast<size_t>(x[0]) )
481                                ok &= (y[i] == 0.);
482                        else    ok &= (y[i] == x[1]);
483                }
484
485                F.optimize();
486
487                // Check number of VecAD vectors plus number of VecAD elements
488                ok &= (F.size_VecAD() == 1 + m); 
489                y = F.Forward(0, x);
490                for(i = 0; i < m; i++)
491                {       if( i != static_cast<size_t>(x[0]) )
492                                ok &= (y[i] == 0.);
493                        else    ok &= (y[i] == x[1]);
494                }
495               
496                return ok;
497        }
498        bool depend_three(void)
499        {       // Power function is a special case for optimize
500                bool ok = true;
501                using CppAD::AD;
502                using CppAD::vector;
503
504                size_t n = 3;
505                size_t j;
506       
507                vector< AD<double> >    X(n), Y(n);
508                vector<double>          x(n), y(n); 
509       
510                for(j = 0; j < n; j++)
511                        X[j] = x[j] = double(j+2);
512       
513                CppAD::Independent(X);
514                       
515                Y[0] = pow(X[0], 2.0);
516                Y[1] = pow(2.0, X[1]);
517                Y[2] = pow(X[0], X[1]);
518       
519                CppAD::ADFun<double> F(X, Y);
520                F.optimize();
521                y = F.Forward(0, x);
522
523                // Use identically equal because the result of the operations
524                // have been stored as double and gaurd bits have been dropped.
525                // (This may not be true for some compiler in the future).
526                for(j = 0; j < n; j++)
527                        ok &= ( y[j] == Value(Y[j]) );
528
529                // check reverse mode derivative
530                vector<double>   w(n), dw(n); 
531                w[0] = 0.;
532                w[1] = 0.;
533                w[2] = 1.;
534                dw = F.Reverse(1, w);
535
536                double eps = 20. * std::numeric_limits<double>::epsilon();
537                double check = x[1] * pow( x[0], x[1] - 1. );
538                ok &= CppAD::NearEqual( dw[0], check, eps, eps );
539
540                check = log( x[0] ) * pow( x[0], x[1] );
541                ok &= CppAD::NearEqual( dw[1], check, eps, eps );
542
543                check = 0.;
544                ok &= CppAD::NearEqual( dw[2], check, eps, eps );
545       
546                return ok;
547        }
548        // ===================================================================
549        // Test duplicate operation analysis
550
551        template <class Vector>
552        void duplicate_fun
553        (const Vector& x, Vector& y, size_t& original, size_t& opt)
554        {       typedef typename Vector::value_type Scalar;
555                original = 0;
556                opt      = 0;
557
558                // unary operator where operand is arg[0] and one result
559                Scalar a1 = CppAD::exp(x[0]); 
560                original += 1;
561                opt      += 1;
562
563                // unary operator where operand is arg[0] and two results
564                Scalar b1 = CppAD::sin(x[1]);
565                original += 2;
566                opt      += 2;
567
568                // non-commutative binary operator where left is a variable
569                // and right is a parameter
570                Scalar c1 = x[2] - 3.;
571                original += 1;
572                opt      += 1;
573
574                // non-commutative binary operator where left is a parameter
575                // and right is a variable
576                Scalar d1 = 3. / x[3];
577                original += 1;
578                opt      += 1;
579
580                // non-commutative binary operator where left is a variable
581                // and right is a variable
582                Scalar e1 = pow(x[3], x[4]);
583                original += 3;
584                opt      += 3;
585
586                // commutative binary operator where  left is a variable
587                // and right is a parameter
588                Scalar f1 = x[5] * 5.;
589                original += 1;
590                opt      += 1;
591
592                // commutative binary operator where  left is a variable
593                // and right is a variable
594                Scalar g1 = x[5] + x[6];
595                original += 1;
596                opt      += 1;
597
598                // duplicate variables
599                Scalar a2 = CppAD::exp(x[0]);
600                Scalar b2 = CppAD::sin(x[1]);  // counts for 2 variables
601                Scalar c2 = x[2] - 3.;
602                Scalar d2 = 3. / x[3];
603                Scalar e2 = pow(x[3], x[4]);   // counts for 3 variables
604                Scalar f2 = 5. * x[5];
605                Scalar g2 = x[6] + x[5];
606                original += 10;
607
608                // result vector
609                y[0] = a1 * a2;
610                y[1] = b1 * b2;
611                y[2] = c1 * c2;
612                y[3] = d1 * d2;
613                y[4] = e1 * e2;
614                y[5] = f1 * f2;
615                y[6] = g1 * g2;
616                original += 7;
617                opt      += 7;
618
619                return;
620        }
621        bool duplicate_one(void)
622        {
623                bool ok = true;
624                using CppAD::AD;
625                size_t original;
626                size_t opt;
627                size_t i, j;
628       
629                // domain space vector
630                size_t n  = 7;
631                CppAD::vector< AD<double> > X(n);
632                for(j = 0; j < n; j++)
633                        X[j] = 1. / double(j + 1); 
634       
635                // declare independent variables and start tape recording
636                CppAD::Independent(X);
637       
638                // range space vector
639                size_t m = n;
640                CppAD::vector< AD<double> > Y(m);
641                duplicate_fun(X, Y, original, opt);
642       
643                // create f: X -> Y and stop tape recording
644                CppAD::ADFun<double> F;
645                F.Dependent(X, Y); 
646       
647                CppAD::vector<double> x(n), y(m), check(m);
648                for(j = 0; j < n; j++)
649                        x[j] = Value(X[j]);
650                y = F.Forward(0, x);
651                duplicate_fun(x, check, original, opt);
652                for(i = 0; i < m; i++)
653                        ok &= (y[i] == check[i]);
654       
655                // Check size before optimization
656                ok &= F.size_var() == (n + 1 + original);
657       
658                // Optimize the operation sequence
659                F.optimize();
660       
661                // Check size after optimization
662                ok &= F.size_var() == (n + 1 + opt);
663       
664                // check result now
665                // (should have already been checked if NDEBUG not defined)
666                y = F.Forward(0, x);
667                for(i = 0; i < m; i++)
668                        ok &= (y[i] == check[i]);
669       
670                return ok;
671        }
672        // -------------------------------------------------------------------
673        bool duplicate_two(void)
674        {       // test that duplicate expression removal is relative to
675                // new and not just old argument indices.
676                bool ok = true;
677                using CppAD::AD;
678                size_t i, j;
679
680                // domain space vector
681                size_t n  = 1;
682                CppAD::vector< AD<double> > X(n);
683                for(j = 0; j < n; j++)
684                        X[j] = double(j + 2); 
685
686                // range space vector
687                size_t m = 1;
688                CppAD::vector< AD<double> > Y(m);
689
690                // declare independent variables and start tape recording
691                CppAD::Independent(X);
692
693                // create a new variable
694                AD<double> A1 = X[0] - 2.;
695
696                // create a duplicate variable
697                AD<double> A2 = X[0] - 2.;
698
699                // create a new variable using first version of duplicate
700                AD<double> B1 = A1 / 2.;
701
702                // create a duplicate that can only be dectected using new
703                // argument indices
704                AD<double> B2 = A2 / 2.; 
705
706                // Make a new variable for result
707                // and make it depend on all the variables
708                Y[0] = B1 + B2;
709
710                // create f: X -> Y and stop tape recording
711                CppAD::ADFun<double> F;
712                F.Dependent(X, Y); 
713
714                // check number of variables in original function
715                ok &= (F.size_var() ==  1 + n + m + 4 ); 
716       
717                CppAD::vector<double> x(n), y(m);
718                for(j = 0; j < n; j++)
719                        x[j] = double(j + 2);
720
721                y   = F.Forward(0, x);
722                for(i = 0; i < m; i++)
723                        ok &= ( y[i] == Value( Y[i] ) );
724
725                F.optimize();
726
727                // check number of variables  in optimized version
728                ok &= (F.size_var() == 1 + n + m + 2 ); 
729
730                y   = F.Forward(0, x);
731                for(i = 0; i < m; i++)
732                        ok &= ( y[i] == Value( Y[i] ) );
733
734                return ok;
735        }
736        // -------------------------------------------------------------------
737        bool duplicate_three(void)
738        {       // test that duplicate expression removal is relative to
739                // new and not just old argument indices (commutative case).
740                bool ok = true;
741                using CppAD::AD;
742                size_t i, j;
743
744                // domain space vector
745                size_t n  = 1;
746                CppAD::vector< AD<double> > X(n);
747                for(j = 0; j < n; j++)
748                        X[j] = double(j + 2); 
749
750                // range space vector
751                size_t m = 1;
752                CppAD::vector< AD<double> > Y(m);
753
754                // declare independent variables and start tape recording
755                CppAD::Independent(X);
756
757                // create a new variable
758                AD<double> A1 = X[0] + 2.;
759
760                // create a duplicate variable
761                AD<double> A2 = 2. + X[0];
762
763                // create a new variable using first version of duplicate
764                AD<double> B1 = A1 * 2.;
765
766                // create a duplicate that can only be dectected using new
767                // argument indices
768                AD<double> B2 = 2. * A2; 
769
770                // Make a new variable for result
771                // and make it depend on all the variables
772                Y[0] = B1 + B2;
773
774                // create f: X -> Y and stop tape recording
775                CppAD::ADFun<double> F;
776                F.Dependent(X, Y); 
777
778                // check number of variables in original function
779                ok &= (F.size_var() ==  1 + n + m + 4 ); 
780       
781                CppAD::vector<double> x(n), y(m);
782                for(j = 0; j < n; j++)
783                        x[j] = double(j + 2);
784
785                y   = F.Forward(0, x);
786                for(i = 0; i < m; i++)
787                        ok &= ( y[i] == Value( Y[i] ) );
788
789                F.optimize();
790
791                // check number of variables  in optimized version
792                ok &= (F.size_var() == 1 + n + m + 2 ); 
793
794                y   = F.Forward(0, x);
795                for(i = 0; i < m; i++)
796                        ok &= ( y[i] == Value( Y[i] ) );
797
798                return ok;
799        }
800        // -------------------------------------------------------------------
801        bool duplicate_four(void)
802        {       // Check that unary expression matching not only checks hash code,
803                // and operator, but also operand (old bug that has been fixed).
804                bool ok = true;
805                using CppAD::AD;
806                size_t j;
807
808                // domain space vector
809                size_t n  = 1;
810                CppAD::vector< AD<double> > X(n);
811                X[0] = 1.;
812
813                // range space vector
814                size_t m = 1;
815                CppAD::vector< AD<double> > Y(m);
816
817                // declare independent variables and start tape recording
818                CppAD::Independent(X);
819
820                // check a huge number of same operation with different operands
821                size_t n_operations = std::min(
822                        size_t(CPPAD_HASH_TABLE_SIZE) + 5,
823                        size_t(std::numeric_limits<CPPAD_TAPE_ADDR_TYPE>::max()) - 5
824                );
825                Y[0] = X[0];
826                for(j = 0; j < n_operations; j++)
827                        Y[0] = abs(Y[0]);
828
829                // create f: X -> Y and stop tape recording
830                CppAD::ADFun<double> F;
831                F.Dependent(X, Y); 
832
833                // check number of variables in original function
834                ok &= (F.size_var() ==  1 + n + n_operations ); 
835       
836                CppAD::vector<double> x(n), y(m);
837                x[0] = 1.;
838
839                y   = F.Forward(0, x);
840                ok &= ( y[0] == Value( Y[0] ) );
841
842                F.optimize();
843
844                // check same number of variables in optimized version
845                ok &= (F.size_var() == 1 + n + n_operations ); 
846
847                y   = F.Forward(0, x);
848                ok &= ( y[0] == Value( Y[0] ) );
849
850                return ok;
851        }
852        // ====================================================================
853        bool cummulative_sum(void)
854        {       // test conversion of a sequence of additions and subtraction
855                // to a cummulative summation sequence.
856                bool ok = true;
857                using CppAD::AD;
858                size_t i, j;
859
860                // domain space vector
861                size_t n  = 7;
862                CppAD::vector< AD<double> > X(n);
863                for(j = 0; j < n; j++)
864                        X[j] = double(j + 2); 
865
866                size_t n_original = 1 + n;
867                size_t n_optimize = 1 + n;
868
869                // range space vector
870                size_t m = 2;
871                CppAD::vector< AD<double> > Y(m);
872
873                // declare independent variables and start tape recording
874                CppAD::Independent(X);
875
876                // Operations inside of optimize_cadd
877                Y[0] = 5. + (X[0] + X[1]) + (X[1] - X[2]) // Addvv, Subvv
878                     + (X[2] - 1.) + (2. - X[3])   // Subvp, Subpv
879                     + (X[4] + 3.) + (4. + X[5]);  // Addpv, Addpv (no Addvp)
880                n_original += 12;
881                n_optimize += 1;
882
883
884                // Operations inside of optimize_csub
885                Y[1] = 5. - (X[1] + X[2]) - (X[2] - X[3]) // Addvv, Subvv
886                     - (X[3] - 1.) - (2. - X[4])   // Subvp, Subpv
887                     - (X[5] + 3.) - (4. + X[6]);  // Addpv, Addpv (no Addvp)
888                n_original += 12;
889                n_optimize += 1;
890
891                CppAD::ADFun<double> F;
892                F.Dependent(X, Y); 
893
894                // check number of variables in original function
895                ok &= (F.size_var() ==  n_original ); 
896       
897                CppAD::vector<double> x(n), y(m);
898                for(j = 0; j < n; j++)
899                        x[j] = double(j + 2);
900
901                y   = F.Forward(0, x);
902                for(i = 0; i < m; i++)
903                        ok &= ( y[i] == Value( Y[i] ) );
904
905                F.optimize();
906
907                // check number of variables  in optimized version
908                ok &= (F.size_var() == n_optimize ); 
909
910                y   = F.Forward(0, x);
911                for(i = 0; i < m; i++)
912                        ok &= ( y[i] == Value( Y[i] ) );
913
914                return ok;
915        }
916        // -------------------------------------------------------------------
917        bool forward_csum(void)
918        {       bool ok = true;
919       
920                using namespace CppAD;
921       
922                // independent variable vector
923                CppAD::vector< AD<double> > X(2);
924                X[0] = 0.; 
925                X[1] = 1.;
926                Independent(X);
927       
928                // compute sum of elements in X
929                CppAD::vector< AD<double> > Y(1);
930                Y[0] = X[0] + X[0] + X[1];
931       
932                // create function object F : X -> Y
933                ADFun<double> F(X, Y);
934       
935                // now optimize the operation sequence
936                F.optimize();
937       
938                // use zero order to evaluate F[ (3, 4) ]
939                CppAD::vector<double>  x0( F.Domain() );
940                CppAD::vector<double>  y0( F.Range() );
941                x0[0]    = 3.;
942                x0[1]    = 4.;
943                y0       = F.Forward(0, x0);
944                ok      &= NearEqual(y0[0] , x0[0]+x0[0]+x0[1], 1e-10, 1e-10);
945       
946                // evaluate derivative of F in X[0] direction
947                CppAD::vector<double> x1( F.Domain() );
948                CppAD::vector<double> y1( F.Range() );
949                x1[0]    = 1.;
950                x1[1]    = 0.;
951                y1       = F.Forward(1, x1);
952                ok      &= NearEqual(y1[0] , x1[0]+x1[0]+x1[1], 1e-10, 1e-10);
953       
954                // evaluate second derivative of F in X[0] direction
955                CppAD::vector<double> x2( F.Domain() );
956                CppAD::vector<double> y2( F.Range() );
957                x2[0]       = 0.;
958                x2[1]       = 0.;
959                y2          = F.Forward(2, x2);
960                double F_00 = 2. * y2[0];
961                ok         &= NearEqual(F_00, 0., 1e-10, 1e-10);
962       
963                return ok;
964        }
965        // -------------------------------------------------------------------
966        bool reverse_csum(void)
967        {       bool ok = true;
968       
969                using namespace CppAD;
970       
971                // independent variable vector
972                CppAD::vector< AD<double> > X(2);
973                X[0] = 0.; 
974                X[1] = 1.;
975                Independent(X);
976       
977                // compute sum of elements in X
978                CppAD::vector< AD<double> > Y(1);
979                Y[0] = X[0] - (X[0] - X[1]);
980       
981                // create function object F : X -> Y
982                ADFun<double> F(X, Y);
983       
984                // now optimize the operation sequence
985                F.optimize();
986       
987                // use zero order to evaluate F[ (3, 4) ]
988                CppAD::vector<double>  x0( F.Domain() );
989                CppAD::vector<double>  y0( F.Range() );
990                x0[0]    = 3.;
991                x0[1]    = 4.;
992                y0       = F.Forward(0, x0);
993                ok      &= NearEqual(y0[0] , x0[0]-x0[0]+x0[1], 1e-10, 1e-10);
994       
995                // evaluate derivative of F
996                CppAD::vector<double> dF( F.Domain() );
997                CppAD::vector<double> w( F.Range() );
998                w[0]    = 1.;
999                dF      = F.Reverse(1, w);
1000                ok     &= NearEqual(dF[0] , 0., 1e-10, 1e-10);
1001                ok     &= NearEqual(dF[1] , 1., 1e-10, 1e-10);
1002       
1003                return ok;
1004        }
1005        bool forward_sparse_jacobian()
1006        {       bool ok = true;
1007                using namespace CppAD;
1008       
1009                // dimension of the domain space
1010                size_t n = 3; 
1011       
1012                // dimension of the range space
1013                size_t m = 3;
1014       
1015                // independent variable vector
1016                CppAD::vector< AD<double> > X(n);
1017                X[0] = 2.; 
1018                X[1] = 3.;
1019                X[2] = 4.;
1020                Independent(X);
1021       
1022                // dependent variable vector
1023                CppAD::vector< AD<double> > Y(m);
1024       
1025                // check results vector
1026                CppAD::vector< bool >       Check(m * n);
1027       
1028                // initialize index into Y
1029                size_t index = 0;
1030       
1031                // Y[0]
1032                Y[index]             = X[0] + X[1] + 5.;
1033                Check[index * n + 0] = true;
1034                Check[index * n + 1] = true;
1035                Check[index * n + 2] = false;
1036                index++;
1037       
1038                // Y[1]
1039                Y[index]             = Y[0] - (X[1] + X[2]);
1040                Check[index * n + 0] = true;
1041                Check[index * n + 1] = true;
1042                Check[index * n + 2] = true;
1043                index++;
1044
1045                // Y[2]
1046                // 2DO: There is a subtitle issue that has to do with using reverse
1047                // jacobian sparsity patterns during the optimization process.
1048                // We need an option to include X[0] in the sparsity pattern
1049                // so the optimizer can know it affects the results.
1050                Y[index]             = CondExpLe(X[0], X[1], X[1]+X[1], X[2]-X[2]);
1051                Check[index * n + 0] = false;
1052                Check[index * n + 1] = true;
1053                Check[index * n + 2] = true;
1054                index++;
1055       
1056                // check final index
1057                assert( index == m );
1058       
1059                // create function object F : X -> Y
1060                ADFun<double> F(X, Y);
1061                F.optimize();
1062       
1063                // ---------------------------------------------------------
1064                // dependency matrix for the identity function
1065                CppAD::vector< std::set<size_t> > Sx(n);
1066                size_t i, j;
1067                for(i = 0; i < n; i++)
1068                {       assert( Sx[i].empty() );
1069                        Sx[i].insert(i);
1070                }
1071       
1072                // evaluate the dependency matrix for F(x)
1073                CppAD::vector< std::set<size_t> > Sy(m);
1074                Sy = F.ForSparseJac(n, Sx);
1075       
1076                // check values
1077                bool found;
1078                for(i = 0; i < m; i++)
1079                {       for(j = 0; j < n; j++)
1080                        {       found = Sy[i].find(j) != Sy[i].end();
1081                                ok &= (found == Check[i * n + j]);
1082                        }
1083                }       
1084       
1085                return ok;
1086        }
1087        bool reverse_sparse_jacobian()
1088        {       bool ok = true;
1089                using namespace CppAD;
1090       
1091                // dimension of the domain space
1092                size_t n = 3; 
1093       
1094                // dimension of the range space
1095                size_t m = 3;
1096       
1097                // independent variable vector
1098                CppAD::vector< AD<double> > X(n);
1099                X[0] = 2.; 
1100                X[1] = 3.;
1101                X[2] = 4.;
1102                Independent(X);
1103       
1104                // dependent variable vector
1105                CppAD::vector< AD<double> > Y(m);
1106       
1107                // check results vector
1108                CppAD::vector< bool >       Check(m * n);
1109       
1110                // initialize index into Y
1111                size_t index = 0;
1112       
1113                // Y[0]
1114                Y[index]             = X[0] + X[1] + 5.;
1115                Check[index * n + 0] = true;
1116                Check[index * n + 1] = true;
1117                Check[index * n + 2] = false;
1118                index++;
1119       
1120                // Y[1]
1121                Y[index]             = Y[0] - (X[1] + X[2]);
1122                Check[index * n + 0] = true;
1123                Check[index * n + 1] = true;
1124                Check[index * n + 2] = true;
1125                index++;
1126
1127                // Y[2]
1128                Y[index]             = CondExpLe(X[0], X[1], X[1]+X[1], X[2]-X[2]);
1129                Check[index * n + 0] = false;
1130                Check[index * n + 1] = true;
1131                Check[index * n + 2] = true;
1132                index++;
1133       
1134                // check final index
1135                assert( index == m );
1136       
1137                // create function object F : X -> Y
1138                ADFun<double> F(X, Y);
1139                F.optimize();
1140       
1141                // ----------------------------------------------------------
1142                // dependency matrix for the identity function
1143                CppAD::vector< bool > Py(m * m);
1144                size_t i, j;
1145                for(i = 0; i < m; i++)
1146                {       for(j = 0; j < m; j++)
1147                                Py[ i * m + j ] = (i == j);
1148                }
1149       
1150                // evaluate the dependency matrix for F(x)
1151                CppAD::vector< bool > Px(m * n);
1152                Px = F.RevSparseJac(m, Py);
1153       
1154                // check values
1155                for(i = 0; i < m; i++)
1156                {       for(j = 0; j < n; j++)
1157                                ok &= (Px[i * n + j] == Check[i * n + j]);
1158                }       
1159       
1160                return ok;
1161        }
1162        bool reverse_sparse_hessian(void)
1163        {       bool ok = true;
1164                using CppAD::AD;
1165                size_t i, j;
1166       
1167                size_t n = 3;
1168                CppAD::vector< AD<double> > X(n); 
1169                X[0] = 1.;
1170                X[1] = 2.;
1171                X[2] = 3.;
1172                CppAD::Independent(X);
1173       
1174                size_t m = 1;
1175                CppAD::vector< AD<double> > Y(m);
1176                Y[0] = CondExpGe( X[0], X[1], 
1177                        X[0] + (2. + X[1] + 3.) * X[1], 
1178                        X[0] + (2. + X[2] + 3.) * X[1]
1179                );
1180       
1181                CppAD::vector<bool> check(n * n);
1182                check[0 * n + 0] = false; // partial w.r.t. x[0], x[0]
1183                check[0 * n + 1] = false; //                x[0], x[1]
1184                check[0 * n + 2] = false; //                x[0], x[2]
1185
1186                check[1 * n + 0] = false; // partial w.r.t. x[1], x[0]
1187                check[1 * n + 1] = true;  //                x[1], x[1]
1188                check[1 * n + 2] = true;  //                x[1], x[2]
1189
1190                check[2 * n + 0] = false; // partial w.r.t. x[2], x[0]
1191                check[2 * n + 1] = true;  //                x[2], x[1]
1192                check[2 * n + 2] = false; //                x[2], x[2]
1193       
1194                // create function object F : X -> Y
1195                CppAD::ADFun<double> F(X, Y);
1196                F.optimize();
1197       
1198                // sparsity pattern for the identity function U(x) = x
1199                CppAD::vector<bool> Px(n * n);
1200                for(i = 0; i < n; i++)
1201                        for(j = 0; j < n; j++)
1202                                Px[ i * n + j ] = (i == j);
1203       
1204                // compute sparsity pattern for Jacobian of F(U(x))
1205                CppAD::vector<bool> P_jac(m * n);
1206                P_jac = F.ForSparseJac(n, Px);
1207       
1208                // compute sparsity pattern for Hessian of F_k ( U(x) )
1209                CppAD::vector<bool> Py(m);
1210                CppAD::vector<bool> Pxx(n * n);
1211                Py[0] = true;
1212                Pxx = F.RevSparseHes(n, Py);
1213                // check values
1214                for(i = 0; i < n * n; i++)
1215                        ok &= (Pxx[i] == check[i]);
1216       
1217                return ok;
1218        }
1219        // check that CondExp properly detects dependencies
1220        bool cond_exp_depend(void)
1221        {       bool ok = true;
1222                using CppAD::AD;
1223
1224                AD<double> zero(0.), one(1.), two(2.), three(3.);
1225       
1226                size_t n = 4;
1227                CppAD::vector< AD<double> > X(n); 
1228                X[0] = zero;
1229                X[1] = one;
1230                X[2] = two;
1231                X[3] = three;
1232                CppAD::Independent(X);
1233       
1234                size_t m = 4;
1235                CppAD::vector< AD<double> > Y(m);
1236                Y[0] = CondExpLt(X[0] + .5,  one,  two, three);
1237                Y[1] = CondExpLt(zero, X[1] + .5,  two, three);
1238                Y[2] = CondExpLt(zero,  one, X[2] + .5, three);
1239                Y[3] = CondExpLt(zero,  one,  two,  X[3] + .5);
1240
1241                CppAD::ADFun<double> f(X, Y);
1242                f.optimize();
1243
1244                CppAD::vector<double> x(n), y(m);
1245                size_t i;
1246                for(i = 0; i < n; i++)
1247                        x[i] = double(n - i);
1248                y    = f.Forward(0, x);
1249
1250                if( x[0] + .5 < 1. )
1251                        ok  &= y[0] == 2.;
1252                else    ok  &= y[0] == 3.;
1253                if( 0. < x[1] + .5 )
1254                        ok  &= y[1] == 2.;
1255                else    ok  &= y[1] == 3.;
1256                ok  &= y[2] == x[2] + .5;;
1257                ok  &= y[3] == 2.;
1258
1259                return ok;
1260        }
1261        // -------------------------------------------------------------------
1262        void my_union(
1263                std::set<size_t>&         result  ,
1264                const std::set<size_t>&   left    ,
1265                const std::set<size_t>&   right   )
1266        {       std::set<size_t> temp;
1267                std::set_union(
1268                        left.begin()              ,
1269                        left.end()                ,
1270                        right.begin()             ,
1271                        right.end()               ,
1272                        std::inserter(temp, temp.begin())
1273                );
1274                result.swap(temp);
1275        }
1276
1277        bool old_atomic_forward(
1278                size_t                         id ,
1279                size_t                          k , 
1280                size_t                          n ,
1281                size_t                          m ,
1282                const CppAD::vector<bool>&     vx ,
1283                CppAD::vector<bool>&           vy ,
1284                const CppAD::vector<double>&   tx , 
1285                CppAD::vector<double>&         ty )
1286        {       assert(n == 3 && m == 2);
1287                if( k > 0 ) 
1288                        return false;
1289
1290                // y[0] = x[0] + x[1]
1291                ty[0] = tx[0] + tx[1];
1292
1293                // y[1] = x[1] + x[2]
1294                ty[1] = tx[1] + tx[2];
1295               
1296                if( vy.size() > 0 )
1297                {       vy[0] = (vx[0] | vx[1]);
1298                        vy[1] = (vx[1] | vx[2]);
1299                }
1300                return true; 
1301        }
1302
1303        bool old_atomic_reverse(
1304                size_t                         id ,
1305                size_t                          k , 
1306                size_t                          n , 
1307                size_t                          m , 
1308                const CppAD::vector<double>&   tx , 
1309                const CppAD::vector<double>&   ty ,
1310                CppAD::vector<double>&         px ,
1311                const CppAD::vector<double>&   py )
1312        {       return false; }
1313
1314        bool old_atomic_for_jac_sparse(
1315                size_t                                  id ,
1316                size_t                                   n ,
1317                size_t                                   m ,
1318                size_t                                   q ,
1319                const CppAD::vector< std::set<size_t> >& r ,
1320                CppAD::vector< std::set<size_t>  >&      s )
1321        {       return false; }
1322
1323        bool old_atomic_rev_jac_sparse(
1324                size_t                                  id ,
1325                size_t                                   n ,
1326                size_t                                   m ,
1327                size_t                                   q ,
1328                CppAD::vector< std::set<size_t> >&       r ,
1329                const CppAD::vector< std::set<size_t> >& s )
1330        {       assert(n == 3 && m == 2);
1331                r[0].clear();
1332                r[1].clear();
1333                r[2].clear();
1334                // y[0] = x[0] + x[1]
1335                my_union(r[0], r[0], s[0]);
1336                my_union(r[1], r[1], s[0]);
1337                // y[1] = x[1] + x[2]
1338                my_union(r[1], r[1], s[1]);
1339                my_union(r[2], r[2], s[1]);
1340
1341                return true; 
1342        }
1343
1344        bool old_atomic_rev_hes_sparse(
1345                size_t                                  id ,
1346                size_t                                   n ,
1347                size_t                                   m ,
1348                size_t                                   q ,
1349                const CppAD::vector< std::set<size_t> >& r ,
1350                const CppAD::vector<bool>&               s ,
1351                CppAD::vector<bool>&                     t ,
1352                const CppAD::vector< std::set<size_t> >& u ,
1353                CppAD::vector< std::set<size_t> >&       v )
1354        {       return false; }
1355
1356        CPPAD_USER_ATOMIC(
1357                my_old_atomic             ,
1358                CppAD::vector              ,
1359                double                     ,
1360                old_atomic_forward        ,
1361                old_atomic_reverse        ,
1362                old_atomic_for_jac_sparse ,
1363                old_atomic_rev_jac_sparse ,
1364                old_atomic_rev_hes_sparse
1365        )
1366
1367        bool old_atomic_test(void)
1368        {       bool ok = true;
1369
1370                using CppAD::AD;
1371                size_t j;
1372                size_t n = 3;
1373                size_t m = 2;
1374                CppAD::vector< AD<double> > ax(n), ay(m), az(m);
1375                for(j = 0; j < n; j++)
1376                        ax[j] = AD<double>(j + 1);
1377                CppAD::Independent(ax);
1378
1379                size_t id = 0;
1380                // first call should stay in the tape
1381                my_old_atomic(id++, ax, ay);
1382                // second call will not get used
1383                my_old_atomic(id++, ax, az);
1384                // create function
1385                CppAD::ADFun<double> g(ax, ay);
1386                // should have 1 + n + m + m varaibles
1387                ok &= g.size_var() == (1 + n + m + m);
1388                g.optimize();
1389                // should have 1 + n + m varaibles
1390                ok &= g.size_var() == (1 + n + m);
1391
1392                // now test that the optimized function gives same results
1393                CppAD::vector<double> x(n), y(m);
1394                for(j = 0; j < n; j++)
1395                        x[j] = (j + 1) * (j + 1);
1396                y = g.Forward(0, x);
1397                // y[0] = x[0] + x[1]
1398                ok &= (y[0] == x[0] + x[1]);
1399                // y[1] = x[1] + x[2]
1400                ok &= (y[0] == x[0] + x[1]);
1401
1402                return ok;
1403        }
1404        bool not_identically_equal(void)
1405        {       bool ok = true;
1406                using CppAD::AD;
1407
1408                // independent variable vector
1409                size_t n = 5;
1410                CppAD::vector< AD<double> > ax(n);
1411                size_t j;
1412                for(j = 0; j < n; j++)
1413                        ax[j] = 1. / 3.;
1414                CppAD::Independent(ax);
1415       
1416                // dependent variable vector
1417                size_t m = 1;
1418                CppAD::vector< AD<double> > ay(m);
1419                ay[0]       = 0.;
1420                for(j = 0; j < n; j++)
1421                {       if( j % 2 == 0 )
1422                                ay[0] += ax[j];
1423                        else    ay[0] -= ax[j];
1424                }
1425                CppAD::ADFun<double> f(ax, ay);
1426       
1427                // Used to fail assert in optimize that forward mode results
1428                // are identically equal
1429                f.optimize();
1430       
1431                return ok;
1432        }
1433}
1434
1435bool optimize(void)
1436{       bool ok = true;
1437        atomic_sparsity_option = CppAD::atomic_base<double>::bool_sparsity_enum;
1438        for(size_t i = 0; i < 2; i++)
1439        {       // check conditional expression sparsity pattern
1440                // (used to optimize calls to atomic functions).
1441                ok     &= atomic_cond_exp_sparsity();
1442                // check optimizing out entire atomic function
1443                ok     &= atomic_cond_exp();
1444                // check optimizing out atomic arguments
1445                ok     &= atomic_no_used();
1446                ok     &= atomic_arguments();
1447                atomic_sparsity_option = 
1448                        CppAD::atomic_base<double>::set_sparsity_enum;
1449        }
1450        // check nested conditional expressions
1451        ok     &= nested_cond_exp();
1452        // check reverse dependency analysis optimization
1453        ok     &= depend_one();
1454        ok     &= depend_two();
1455        ok     &= depend_three();
1456        // check removal of duplicate expressions
1457        ok     &= duplicate_one();
1458        ok     &= duplicate_two();
1459        ok     &= duplicate_three();
1460        ok     &= duplicate_four();
1461        // convert sequence of additions to cummulative summation
1462        ok     &= cummulative_sum();
1463        ok     &= forward_csum();
1464        ok     &= reverse_csum();
1465        // sparsity patterns
1466        ok     &= forward_sparse_jacobian();
1467        ok     &= reverse_sparse_jacobian();
1468        ok     &= reverse_sparse_hessian();
1469        // check that CondExp properly detects dependencies
1470        ok     &= cond_exp_depend();
1471        // check old_atomic functions
1472        ok     &= old_atomic_test();
1473        // case where results are not identically equal
1474        ok     &= not_identically_equal();
1475        //
1476        CppAD::user_atomic<double>::clear();
1477        return ok;
1478}
Note: See TracBrowser for help on using the repository browser.