File: compare_op.cpp

package info (click to toggle)
cppad 2026.00.00.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 11,584 kB
  • sloc: cpp: 112,960; sh: 6,146; ansic: 179; python: 71; sed: 12; makefile: 10
file content (137 lines) | stat: -rw-r--r-- 4,463 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-22 Bradley M. Bell
// ----------------------------------------------------------------------------
/*
{xrst_begin optimize_compare_op.cpp}

Optimize Comparison Operators: Example and Test
###############################################

See Also
********
:ref:`cond_exp.cpp-name`

{xrst_literal
   // BEGIN C++
   // END C++
}

{xrst_end optimize_compare_op.cpp}
*/
// BEGIN C++
# include <cppad/cppad.hpp>
namespace {
   struct tape_size { size_t n_var; size_t n_op; };

   template <class Vector> void fun(
      const std::string& options ,
      const Vector& x, Vector& y, tape_size& before, tape_size& after
   )
   {  typedef typename Vector::value_type scalar;

      // phantom variable with index 0 and independent variables
      // begin operator, independent variable operators and end operator
      before.n_var = 1 + x.size(); before.n_op  = 2 + x.size();
      after.n_var  = 1 + x.size(); after.n_op   = 2 + x.size();

      // Create a variable that is is only used in the comparison operation
      // It is not used when the comparison operator is not included
      scalar one = 1. / x[0];
      before.n_var += 1; before.n_op += 1;
      after.n_var  += 0; after.n_op  += 0;
      // If we keep comparison operators, we must compute their operands
      if( options.find("no_compare_op") == std::string::npos )
      {  after.n_var += 1;  after.n_op += 1;
      }

      // Create a variable that is used by the result
      scalar two = x[0] * 5.;
      before.n_var += 1; before.n_op += 1;
      after.n_var  += 1; after.n_op += 1;

      // Only one variable created for this comparison operation
      // but the value depends on which branch is taken.
      scalar three;
      if( one < x[0] )        // comparison operator
         three = two / 2.0;  // division operator
      else
         three = 2.0 * two;  // multiplication operator
      // comparison and either division of multiplication operator
      before.n_var += 1; before.n_op += 2;
      // comparison operator depends on optimization options
      after.n_var += 1;  after.n_op += 1;
      // check if we are keeping the comparison operator
      if( options.find("no_compare_op") == std::string::npos )
         after.n_op += 1;

      // results for this operation sequence
      y[0] = three;
      before.n_var += 0; before.n_op  += 0;
      after.n_var  += 0; after.n_op   += 0;
   }
}

bool compare_op(void)
{  bool ok = true;
   using CppAD::AD;
   using CppAD::NearEqual;
   double eps10 = 10.0 * std::numeric_limits<double>::epsilon();

   // domain space vector
   size_t n  = 1;
   CPPAD_TESTVECTOR(AD<double>) ax(n);
   ax[0] = 0.5;

   // range space vector
   size_t m = 1;
   CPPAD_TESTVECTOR(AD<double>) ay(m);

   for(size_t k = 0; k < 2; k++)
   {  // optimization options
      std::string options = "";
      if( k == 0 )
         options = "no_compare_op";

      // declare independent variables and start tape recording
      CppAD::Independent(ax);

      // compute function value
      tape_size before, after;
      fun(options, ax, ay, before, after);

      // create f: x -> y and stop tape recording
      CppAD::ADFun<double> f(ax, ay);
      ok &= f.size_order() == 1; // this constructor does 0 order forward
      ok &= f.size_var() == before.n_var;
      ok &= f.size_op() == before.n_op;

      // Optimize the operation sequence
      f.optimize(options);
      ok &= f.size_order() == 0; // 0 order forward not present
      ok &= f.size_var() == after.n_var;
      ok &= f.size_op() == after.n_op;

      // Check result for a zero order calculation for a different x,
      // where the result of the comparison is he same.
      CPPAD_TESTVECTOR(double) x(n), y(m), check(m);
      x[0] = 0.75;
      y    = f.Forward(0, x);
      if ( options == "" )
         ok  &= f.compare_change_number() == 0;
      fun(options, x, check, before, after);
      ok &= NearEqual(y[0], check[0], eps10, eps10);

      // Check case where result of the comparison is different
      // (hence one needs to re-tape to get correct result)
      x[0] = 2.0;
      y    = f.Forward(0, x);
      if ( options == "" )
         ok  &= f.compare_change_number() == 1;
      fun(options, x, check, before, after);
      ok  &= std::fabs(y[0] - check[0]) > 0.5;
   }
   return ok;
}

// END C++