1 # ifndef CPPAD_LOCAL_OPTIMIZE_GET_CEXP_INFO_HPP
2 # define CPPAD_LOCAL_OPTIMIZE_GET_CEXP_INFO_HPP
3 /* --------------------------------------------------------------------------
4 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
5
6 CppAD is distributed under the terms of the
7 Eclipse Public License Version 2.0.
8
9 This Source Code may also be made available under the following
10 Secondary License when the conditions for such availability set forth
11 in the Eclipse Public License, Version 2.0 are satisfied:
12 GNU General Public License, Version 2.0 or later.
13 ---------------------------------------------------------------------------- */
14
15 # include <cppad/local/optimize/match_op.hpp>
16 # include <cppad/local/optimize/cexp_info.hpp>
17 # include <cppad/local/optimize/usage.hpp>
18
19 // BEGIN_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
20 namespace CppAD { namespace local { namespace optimize {
21
22 /*!
23 $begin optimize_get_cexp_info.hpp$$
24 $spell
25 cexp
26 itr
27 op
28 iterator
29 bool
30 Exp
31 deallocate
32 Funap
33 Funav
34 Funrp
35 Funrv
36 num
37 var
38 $$
39
40 $section Information for Each Conditional Expression$$
41
42 $head Syntax$$
43 $codei%get_cexp_info(
44 %play%,
45 %random_itr%,
46 %op_previous%,
47 %op_usage%,
48 %cexp2op%,
49 %cexp_set%,
50 %cexp_info%,
51 %skip_op_true%,
52 %skip_op_false%
53 )%$$
54
55 $head Prototype$$
56 $srcthisfile%
57 0%// BEGIN_PROTOTYPE%// END_PROTOTYPE%1
58 %$$
59
60
61 $head Restrictions$$
62 Do not call this routine unless you are optimizing conditional expressions
63 and there are conditional expressions in the operation sequence.
64
65 $head Base$$
66 base type for the operator; i.e., this operation was recorded
67 using AD<Base> and computations by this routine are done using type Base.
68
69 $head play$$
70 This is the old operation sequence.
71
72 $head random_itr$$
73 This is a random iterator for the old operation sequence.
74
75 $head cexp2op$$
76 This is the number of conditional expressions in the operation sequence
77 and must be non-zero.
78
79 $head cexp_set$$
80 This is a vector of sets, the i-th set, set[i],
81 is a set of elements for the i-th operator.
82 If e is an element of set[i], let j = e / 2 and k = e % 2.
83 If the comparison for the j-th conditional expression is equal to bool(k),
84 the i-th operator can be skipped (is not used by any of the results).
85 Note that j indexes the subset of operators that are conditional expressions
86 in the old operation sequence.
87
88 $head cexp_info$$
89 The input size of this vector must be zero.
90 Upon return cexp_info has size equal to the number of conditional expressions
91 in the operation sequence; i.e., the number of CExpOp operators.
92 The value cexp_info[j] is the information corresponding to the j-th
93 conditional expression in the operation sequence.
94 This vector is in the same order as the operation sequence; i.e.
95 if j1 > j2, cexp_info[j1].i_op > cexp_info[j2].i_op.
96 Note that skip_op_true and skip_op_false could be part of this structure,
97 but then we would allocate and deallocate two vectors for each conditional
98 expression in the operation sequence.
99
100 $head skip_op_true$$
101 This vector of sets is empty on input.
102 Upon return, the j-th set is the operators that are not used when
103 comparison result for cexp_info[j] is true.
104 Note that FunapOp, FunavOp, FunrpOp, and FunrvOp, are not in this
105 set and should be skipped when the corresponding AFunOp are skipped.
106
107 $head skip_op_false$$
108 This vector of sets is empty on input.
109 Upon return, the j-th set is the operators that are not used when
110 comparison result for cexp_info[j] is false.
111 Note that FunapOp, FunavOp, FunrpOp, and FunrvOp, are not in this
112 set and should be skipped when the corresponding AFunOp are skipped.
113
114 $head op_previous$$
115 This argument has size equal to the number of operators
116 in the operation sequence; i.e., num_op = play->nun_var_rec().
117 If op_previous[i] == 0, no replacement was found for the i-th operator.
118 If op_previous[i] != 0, op_usage[ op_previous[i] ] == usage_t(yes_usage).
119
120 $head op_usage$$
121 This argument has size equal to the number of operators
122 in the operation sequence; i.e., num_op = play->nun_var_rec().
123 The value op_usage[i] is the usage for
124 the i-th operator in the operation sequence.
125
126 $end
127 */
128
129 // BEGIN_PROTOTYPE
130 template <class Addr, class Base>
get_cexp_info(const player<Base> * play,const play::const_random_iterator<Addr> & random_itr,const pod_vector<addr_t> & op_previous,const pod_vector<usage_t> & op_usage,const pod_vector<addr_t> & cexp2op,const sparse::list_setvec & cexp_set,vector<struct_cexp_info> & cexp_info,sparse::list_setvec & skip_op_true,sparse::list_setvec & skip_op_false)131 void get_cexp_info(
132 const player<Base>* play ,
133 const play::const_random_iterator<Addr>& random_itr ,
134 const pod_vector<addr_t>& op_previous ,
135 const pod_vector<usage_t>& op_usage ,
136 const pod_vector<addr_t>& cexp2op ,
137 const sparse::list_setvec& cexp_set ,
138 vector<struct_cexp_info>& cexp_info ,
139 sparse::list_setvec& skip_op_true ,
140 sparse::list_setvec& skip_op_false )
141 // END_PROTOTYPE
142 {
143 CPPAD_ASSERT_UNKNOWN( cexp_set.n_set() > 0 );
144 CPPAD_ASSERT_UNKNOWN( cexp_info.size() == 0 );
145
146 // number of operators in the tape
147 const size_t num_op = play->num_op_rec();
148 CPPAD_ASSERT_UNKNOWN( op_usage.size() == num_op );
149 CPPAD_ASSERT_UNKNOWN( op_previous.size() == num_op );
150 //
151 // number of conditional expressions in the tape
152 size_t num_cexp_op = cexp2op.size();
153 //
154 // initialize mapping from variable index to operator index
155 CPPAD_ASSERT_UNKNOWN(
156 size_t( (std::numeric_limits<addr_t>::max)() ) >= num_op
157 );
158 // ----------------------------------------------------------------------
159 // compute cexp_info
160 // ----------------------------------------------------------------------
161 //
162 // initialize information for each conditional expression
163 cexp_info.resize(num_cexp_op);
164 skip_op_true.resize(num_cexp_op, num_op);
165 skip_op_false.resize(num_cexp_op, num_op);
166 //
167 for(size_t i = 0; i < num_cexp_op; i++)
168 { size_t i_op = size_t( cexp2op[i] );
169 CPPAD_ASSERT_UNKNOWN(
170 op_previous[i_op] == 0 || op_usage[i_op] == usage_t(yes_usage)
171 );
172 OpCode op; // operator
173 const addr_t* arg; // arguments
174 size_t i_var; // variable index of first result
175 random_itr.op_info(i_op, op, arg, i_var);
176 CPPAD_ASSERT_UNKNOWN( op == CExpOp );
177 //
178 struct_cexp_info info;
179 info.i_op = addr_t(i_op);
180 info.cop = CompareOp( arg[0] );
181 info.flag = static_cast<unsigned char>(arg[1]);
182 info.left = arg[2];
183 info.right = arg[3];
184 //
185 // max_left_right
186 addr_t index = 0;
187 if( arg[1] & 1 )
188 index = std::max<addr_t>(index, info.left);
189 if( arg[1] & 2 )
190 index = std::max<addr_t>(index, info.right);
191 info.max_left_right = index;
192 //
193 cexp_info[i] = info;
194 };
195 // Determine which operators can be conditionally skipped
196 size_t i_op = 0;
197 while(i_op < num_op)
198 { size_t j_op = i_op;
199 bool keep = op_usage[i_op] != usage_t(no_usage);
200 keep &= op_usage[i_op] != usage_t(csum_usage);
201 keep &= op_previous[i_op] == 0;
202 if( keep )
203 { sparse::list_setvec_const_iterator itr(cexp_set, i_op);
204 if( *itr != cexp_set.end() )
205 { if( play->GetOp(i_op) == AFunOp )
206 { // i_op is the first operations in this atomic function call.
207 // Find the last operation in this call.
208 ++j_op;
209 while( play->GetOp(j_op) != AFunOp )
210 { switch( play->GetOp(j_op) )
211 { case FunapOp:
212 case FunavOp:
213 case FunrpOp:
214 case FunrvOp:
215 break;
216
217 default:
218 CPPAD_ASSERT_UNKNOWN(false);
219 }
220 ++j_op;
221 }
222 }
223 }
224 while( *itr != cexp_set.end() )
225 { size_t element = *itr;
226 size_t index = element / 2;
227 bool compare = bool( element % 2 );
228 if( compare == false )
229 { // cexp_info[index].skip_op_false.push_back(i_op);
230 skip_op_false.post_element(index, i_op);
231 if( j_op != i_op )
232 { // cexp_info[index].skip_op_false.push_back(j_op);
233 skip_op_false.post_element(index, j_op);
234 }
235 }
236 else
237 { // cexp_info[index].skip_op_true.push_back(i_op);
238 skip_op_true.post_element(index, i_op);
239 if( j_op != i_op )
240 { // cexp_info[index].skip_op_true.push_back(j_op);
241 skip_op_true.post_element(index, j_op);
242 }
243 }
244 ++itr;
245 }
246 }
247 CPPAD_ASSERT_UNKNOWN( i_op <= j_op );
248 i_op += (1 + j_op) - i_op;
249 }
250 // process postings for skip_op_false, skip_op_true
251 for(size_t i = 0; i < num_cexp_op; ++i)
252 { skip_op_false.process_post(i);
253 skip_op_true.process_post(i);
254 }
255 return;
256 }
257
258 } } } // END_CPPAD_LOCAL_OPTIMIZE_NAMESPACE
259
260 # endif
261