| 21 | struct tape_size { size_t n_var; size_t n_op; }; |
| 22 | |
| 23 | template <class Vector> void fun( |
| 24 | const Vector& x, Vector& y, tape_size& before, tape_size& after |
| 25 | ) |
| 26 | { typedef typename Vector::value_type scalar; |
| 27 | |
| 28 | // phantom variable with index 0 and independent variables |
| 29 | // begin operator, independent variable operators and end operator |
| 30 | before.n_var = 1 + x.size(); before.n_op = 2 + x.size(); |
| 31 | after.n_var = 1 + x.size(); after.n_op = 2 + x.size(); |
| 32 | |
| 33 | // adding the constant zero does not take any operations |
| 34 | scalar zero = 0.0 + x[0]; |
| 35 | before.n_var += 0; before.n_op += 0; |
| 36 | after.n_var += 0; after.n_op += 0; |
| 37 | |
| 38 | // multiplication by the constant one does not take any operations |
| 39 | scalar one = 1.0 * x[1]; |
| 40 | before.n_var += 0; before.n_op += 0; |
| 41 | after.n_var += 0; after.n_op += 0; |
| 42 | |
| 43 | // multiplication by the constant zero does not take any operations |
| 44 | // and results in the constant zero. |
| 45 | scalar two = 0.0 * x[0]; |
| 46 | |
| 47 | // operations that only involve constants do not take any operations |
| 48 | scalar three = (1.0 + two) * 3.0; |
| 49 | before.n_var += 0; before.n_op += 0; |
| 50 | after.n_var += 0; after.n_op += 0; |
| 51 | |
| 52 | // The optimizer will recognize that zero + one = one + zero |
| 53 | // for all values of x. |
| 54 | scalar four = zero + one; |
| 55 | scalar five = one + zero; |
| 56 | before.n_var += 2; before.n_op += 2; |
| 57 | after.n_var += 1; after.n_op += 1; |
| 58 | |
| 59 | // The optimizer will recognize that sin(x[3]) = sin(x[3]) |
| 60 | // for all values of x. Note that, for computation of derivatives, |
| 61 | // sin(x[3]) and cos(x[3]) are stored on the tape as a pair. |
| 62 | scalar six = sin(x[2]); |
| 63 | scalar seven = sin(x[2]); |
| 64 | before.n_var += 4; before.n_op += 2; |
| 65 | after.n_var += 2; after.n_op += 1; |
| 66 | |
| 67 | // If we used addition here, five + seven = zero + one + seven |
| 68 | // which would get converted to a cumulative summation operator. |
| 69 | scalar eight = five * seven; |
| 70 | before.n_var += 1; before.n_op += 1; |
| 71 | after.n_var += 1; after.n_op += 1; |
| 72 | |
| 73 | // Use two, three, four and six in order to avoid a compiler warning |
| 74 | // Note that addition of two and three does not take any operations. |
| 75 | // Also note that optimizer recognizes four * six == five * seven. |
| 76 | scalar nine = eight + four * six * (two + three); |
| 77 | before.n_var += 3; before.n_op += 3; |
| 78 | after.n_var += 2; after.n_op += 2; |
| 79 | |
| 80 | // results for this operation sequence |