File: compare_change.cpp

package info (click to toggle)
cppad 2025.00.00.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 11,552 kB
  • sloc: cpp: 112,594; sh: 5,972; ansic: 179; python: 71; sed: 12; makefile: 10
file content (195 lines) | stat: -rw-r--r-- 5,524 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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// 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 compare_change.cpp}

CompareChange and Re-Tape: Example and Test
###########################################
This test is run as a separate program so that it does not
mix debug and release versions of the template functions it calls.

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

{xrst_end compare_change.cpp}
*/
// BEGIN C++

# include <cppad/cppad.hpp>

// empty namespace
namespace {
   //
   // Minimum
   template <class Type>
   Type Minimum(const Type &x, const Type &y)
   {  // Use a comparison to compute the min(x, y)
      // (note that CondExp would never require retaping).
      if( x < y )
         return x;
      return y;
   }
   //
   // error_info
   struct error_info {
      bool known;
      int  line;
      std::string file;
      std::string exp;
      std::string msg;
   };
   //
   // error_handler
   void error_handler(
      bool        known       ,
      int         line        ,
      const char *file        ,
      const char *exp         ,
      const char *msg         )
   {  // error handler must not return, so throw an exception
      error_info info;
      info.known = known;
      info.line  = line;
      info.file  = file;
      info.exp   = exp;
      info.msg   = msg;
      throw info;
   }

}
//
// compare_change
bool compare_change(void)
{  bool ok = true;
   using CppAD::AD;

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

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

   // range space vector
   size_t m = 1;
   CPPAD_TESTVECTOR(AD<double>) ay(m);
   ay[0] = Minimum(ax[0], ax[1]);

   // create f: x -> y and stop tape recording
   CppAD::ADFun<double> f(ax, ay);

   // set count to one (not necessry because is its default value)
   f.compare_change_count(1);

   // evaluate zero mode Forward where comparison has the same result
   // as during taping; i.e., x[0] < x[1].
   CPPAD_TESTVECTOR(double) x(n), y(m);
   x[0] = 2.;
   x[1] = 3.;
   y    = f.Forward(0, x);
   ok  &= (y[0] == x[0]);
   ok  &= (y[0] == Minimum(x[0], x[1]));
   ok  &= (f.compare_change_number() == 0);
   ok  &= (f.compare_change_op_index() == 0);

   // evaluate zero mode Forward where comparison has different result
   // as during taping; i.e., x[0] >= x[1].
   x[0] = 3.;
   x[1] = 2.;
   y    = f.Forward(0, x);
   ok  &= (y[0] == x[0]);
   ok  &= (y[0] != Minimum(x[0], x[1]));
   ok  &= (f.compare_change_number() == 1);
   ok  &= (f.compare_change_op_index() > 0 );
   size_t op_index = f.compare_change_op_index();

   // Local block during which default CppAD error handler is replaced.
   // If you do not replace the default CppAD error handler,
   // and you run in the debugger, you will be able to inspect the
   // call stack and see that 'if( x < y )' is where the comparison is.
   bool missed_error = true;
   {  CppAD::ErrorHandler local_error_handler(error_handler);

      std::string check_msg =
         "Operator index equals abort_op_index in Independent";
      try {
         // determine the operation index where the change occurred
         CppAD::Independent(ax, op_index);
         ay[0] = Minimum(ax[0], ax[1]);
# ifdef NDEBUG
         // CppAD does not spend time checking operator index when
         // NDEBUG is defined
         missed_error = false;
         AD<double>::abort_recording();
# endif
      }
      catch( error_info info )
      {  missed_error = false;
         ok          &= info.known;
         ok          &= info.msg == check_msg;
         // Must abort the recording so we can start a new one
         // (and to avoid a memory leak).
         AD<double>::abort_recording();
      }
   }
   ok &= ! missed_error;

   // set count to zero to demonstrate case where comparisons are not checked
   f.compare_change_count(0);
   y    = f.Forward(0, x);
   ok  &= (y[0] == x[0]);
   ok  &= (y[0] != Minimum(x[0], x[1]));
   ok  &= (f.compare_change_number()   == 0);
   ok  &= (f.compare_change_op_index() == 0);

   // now demonstrate that compare_change_number works for an optimized
   // tape (note that compare_change_op_index is always zero after optimize)
   f.optimize();
   f.compare_change_count(1);
   y    = f.Forward(0, x);
   ok  &= (y[0] == x[0]);
   ok  &= (y[0] != Minimum(x[0], x[1]));
   ok  &= (f.compare_change_number()   == 1);
   ok  &= (f.compare_change_op_index() == 0);

   // now retape to get the a tape that agrees with the algorithm
   ax[0] = x[0];
   ax[1] = x[1];
   Independent(ax);
   ay[0] = Minimum(ax[0], ax[1]);
   f.Dependent(ax, ay);
   y    = f.Forward(0, x);
   ok  &= (y[0] == x[1]);
   ok  &= (y[0] == Minimum(x[0], x[1]));
   ok  &= (f.compare_change_number()   == 0);
   ok  &= (f.compare_change_op_index() == 0);

   return ok;
}

// main program that runs this test
int main(void)
{  std::string group = "example/compare_change";
   size_t      width = 20;
   CppAD::test_boolofvoid Run(group, width);

   // This line is used by test_one.sh

   Run( compare_change,    "compare_change"   );
   //
   // check for memory leak
   bool memory_ok = CppAD::thread_alloc::free_all();
   // print summary at end
   bool ok = Run.summary(memory_ok);
   //
   return static_cast<int>( ! ok );
}

// END C++