File: nest_conditional.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 (178 lines) | stat: -rw-r--r-- 5,793 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
// 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_nest_conditional.cpp}

Optimize Nested Conditional Expressions: Example and Test
#########################################################

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

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

{xrst_end optimize_nest_conditional.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 second comparison
      scalar two = 1. + x[0];
      before.n_var += 1; before.n_op += 1;
      after.n_var  += 1; after.n_op  += 1;

      // Conditional skip for second comparison will be inserted here.
      if( options.find("no_conditional_skip") == std::string::npos )
         after.n_op += 1; // for conditional skip operation

      // Create a variable that is is only used in the first comparison
      // (can be skipped when second comparison result is false)
      scalar one = 1. / x[0];
      before.n_var += 1; before.n_op += 1;
      after.n_var  += 1; after.n_op  += 1;

      // Conditional skip for first comparison will be inserted here.
      if( options.find("no_conditional_skip") == std::string::npos )
         after.n_op += 1; // for conditional skip operation

      // value when first comparison if false
      scalar one_false = 5.0;

      // Create a variable that is only used when second comparison is true
      // (can be skipped when it is false)
      scalar one_true = x[0] / 5.0;
      before.n_var += 1; before.n_op += 1;
      after.n_var  += 1; after.n_op  += 1;

      // value when second comparison is false
      scalar two_false = 3.0;

      // First conditional compaison is 1 / x[0] < x[0]
      // is only used when second conditional expression is true
      // (can be skipped when it is false)
      scalar two_true  = CppAD::CondExpLt(one, x[0], one_true, one_false);
      before.n_var += 1; before.n_op += 1;
      after.n_var  += 1; after.n_op  += 1;

      // Second conditional compaison is 1 + x[0] < x[1]
      scalar two_value = CppAD::CondExpLt(two, x[1], two_true, two_false);
      before.n_var += 1; before.n_op += 1;
      after.n_var  += 1; after.n_op  += 1;

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

bool nest_conditional(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  = 2;
   CPPAD_TESTVECTOR(AD<double>) ax(n);
   ax[0] = 0.5;
   ax[1] = 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_conditional_skip";

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

      // compute function computation
      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 case where result of the second comparison is true
      // and first comparison is true
      CPPAD_TESTVECTOR(double) x(n), y(m), check(m);
      x[0] = 1.75;
      x[1] = 4.0;
      y    = f.Forward(0, x);
      fun(options, x, check, before, after);
      ok &= NearEqual(y[0], check[0], eps10, eps10);
      ok  &= f.number_skip() == 0;

      // Check case where result of the second comparison is true
      // and first comparison is false
      x[0] = 0.5;
      x[1] = 4.0;
      y    = f.Forward(0, x);
      fun(options, x, check, before, after);
      ok &= NearEqual(y[0], check[0], eps10, eps10);
      if( options == "" )
         ok  &= f.number_skip() == 1;
      else
         ok &= f.number_skip() == 0;

      // Check case where result of the second comparison is false
      // and first comparison is true
      x[0] = 1.75;
      x[1] = 0.0;
      y    = f.Forward(0, x);
      fun(options, x, check, before, after);
      ok &= NearEqual(y[0], check[0], eps10, eps10);
      if( options == "" )
         ok  &= f.number_skip() == 3;
      else
         ok &= f.number_skip() == 0;

      // Check case where result of the second comparison is false
      // and first comparison is false
      x[0] = 0.5;
      x[1] = 0.0;
      y    = f.Forward(0, x);
      fun(options, x, check, before, after);
      ok &= NearEqual(y[0], check[0], eps10, eps10);
      if( options == "" )
         ok  &= f.number_skip() == 3;
      else
         ok &= f.number_skip() == 0;
   }
   return ok;
}

// END C++