1 /* --------------------------------------------------------------------------
2 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
3
4 CppAD is distributed under the terms of the
5 Eclipse Public License Version 2.0.
6
7 This Source Code may also be made available under the following
8 Secondary License when the conditions for such availability set forth
9 in the Eclipse Public License, Version 2.0 are satisfied:
10 GNU General Public License, Version 2.0 or later.
11 ---------------------------------------------------------------------------- */
12 /*
13 $begin graph_atom_op.cpp$$
14 $spell
15 atom
16 Json
17 $$
18
19 $section C++ AD Graph Atomic Functions: Example and Test$$
20
21 $head Source Code$$
22 $srcthisfile%0%// BEGIN C++%// END C++%1%$$
23
24 $end
25 */
26 // BEGIN C++
27 # include <cppad/cppad.hpp>
28
atom_op(void)29 bool atom_op(void)
30 { bool ok = true;
31 using std::string;
32 // -----------------------------------------------------------------------
33 // Define f_0 (x_0, x_1; p) = x_1 + p_0 * x_0
34 //
35 // This function does not have an atomic function operator
36 // node_1 : p[0]
37 // node_2 : x[0]
38 // node_3 : x[1]
39 // node_4 : p[0] * x[0]
40 // node_5 : x[1] + p[0] * x[0]
41 // y[0] = x[1] + p[0] * x[0]
42 //
43 // C++ graph object
44 CppAD::cpp_graph graph_obj;
45 //
46 // operator being used
47 CppAD::graph::graph_op_enum op_enum;
48 //
49 // set scalars
50 graph_obj.function_name_set("f(x; p)");
51 size_t n_dynamic_ind = 1;
52 graph_obj.n_dynamic_ind_set(n_dynamic_ind);
53 size_t n_variable_ind = 2;
54 graph_obj.n_variable_ind_set(n_variable_ind);
55 //
56 // node_4 : p[0] * x[0]
57 op_enum = CppAD::graph::mul_graph_op;
58 graph_obj.operator_vec_push_back(op_enum);
59 graph_obj.operator_arg_push_back(1);
60 graph_obj.operator_arg_push_back(2);
61 //
62 // node_5 : x[1] + p[0] * x[0]
63 op_enum = CppAD::graph::add_graph_op;
64 graph_obj.operator_vec_push_back(op_enum);
65 graph_obj.operator_arg_push_back(3);
66 graph_obj.operator_arg_push_back(4);
67 //
68 // y[0] = x[1] + p[0] * x[0]
69 graph_obj.dependent_vec_push_back(5);
70 //
71 // f(x, p) = x_1 + p_0 * x_0
72 CppAD::ADFun<float> f;
73 f.from_graph(graph_obj);
74 //
75 ok &= f.Domain() == 2;
76 ok &= f.Range() == 1;
77 ok &= f.size_dyn_ind() == 1;
78 //
79 // A ckhpoint_two function with name f(x; p) is derived from
80 // an atomic_three fucntion with the same name.
81 bool internal_bool = false;
82 bool use_hes_sparsity = false;
83 bool use_base2ad = false;
84 bool use_in_parallel = false;
85 CppAD::chkpoint_two<float> chk_f(f, "f(x; p)",
86 internal_bool, use_hes_sparsity, use_base2ad, use_in_parallel
87 );
88 // -----------------------------------------------------------------------
89 // g (u_0, u_1; p, q) = f(u_0 + q_0, u_1 + q_1, p)
90 // = u_1 + q_1 + p_0 * ( u_0 + q_0 )
91 //
92 // This function has an atomic function operator with name f(x; p)
93 // node_1 : q[0]
94 // node_2 : q[1]
95 // node_3 : u[0]
96 // node_4 : u[1]
97 // node_5 : u[0] + q[0]
98 // node_6 : u[1] + q[1]
99 // node_7 : f( u[0] + q[0], u[1] + q[1]; p)
100 // y[0] = u[1] + q[1] + p[0] * (u[0] + q[0])
101 //
102 graph_obj.initialize();
103 //
104 graph_obj.function_name_set("g(u; p, q)");
105 n_dynamic_ind = 2;
106 graph_obj.n_dynamic_ind_set(n_dynamic_ind);
107 n_variable_ind = 2;
108 graph_obj.n_variable_ind_set(n_variable_ind);
109 //
110 // node_5 : u[0] + q[0]
111 op_enum = CppAD::graph::add_graph_op;
112 graph_obj.operator_vec_push_back(op_enum);
113 graph_obj.operator_arg_push_back(3);
114 graph_obj.operator_arg_push_back(1);
115 //
116 // node_6 : u[1] + q[1]
117 graph_obj.operator_vec_push_back(op_enum);
118 graph_obj.operator_arg_push_back(4);
119 graph_obj.operator_arg_push_back(2);
120 //
121 // node_7 : f( u[0] + q[0], u[1] + q[1]; p)
122 //
123 // name_index, n_result, n_arg come before first_node
124 size_t name_index = graph_obj.atomic_name_vec_size();
125 graph_obj.atomic_name_vec_push_back("f(x; p)");
126 //
127 op_enum = CppAD::graph::atom_graph_op;
128 graph_obj.operator_vec_push_back(op_enum);
129 graph_obj.operator_arg_push_back(name_index); // name_index
130 graph_obj.operator_arg_push_back(1); // n_result
131 graph_obj.operator_arg_push_back(2); // n_node_arg
132 graph_obj.operator_arg_push_back(5); // first node arg
133 graph_obj.operator_arg_push_back(6); // second node arg
134 //
135 // y[0] = u[1] + q[1] + p[0] * (u[0] + q[0])
136 graph_obj.dependent_vec_push_back(7);
137 // ------------------------------------------------------------------------
138 CppAD::ADFun<float> g;
139 g.from_graph(graph_obj);
140 // ------------------------------------------------------------------------
141 ok &= g.Domain() == 2;
142 ok &= g.Range() == 1;
143 ok &= g.size_dyn_ind() == 2;
144 //
145 // set p in g(u; p, q)
146 CPPAD_TESTVECTOR(float) p(1);
147 p[0] = 2.0;
148 chk_f.new_dynamic(p);
149 //
150 // set q in g(u; p, q)
151 CPPAD_TESTVECTOR(float) q(2);
152 q[0] = 3.0;
153 q[1] = 4.0;
154 g.new_dynamic(q);
155 //
156 // evalute g(u; p, q)
157 CPPAD_TESTVECTOR(float) u(2), y(1);
158 u[0] = 5.0;
159 u[1] = 6.0;
160 y = g.Forward(0, u);
161 //
162 // check value
163 ok &= y[0] == u[1] + q[1] + p[0] * (u[0] + q[0]);
164 // ------------------------------------------------------------------------
165 g.to_graph(graph_obj);
166 g.from_graph(graph_obj);
167 // ------------------------------------------------------------------------
168 ok &= g.Domain() == 2;
169 ok &= g.Range() == 1;
170 ok &= g.size_dyn_ind() == 2;
171 //
172 // set p in g(u; p, q)
173 p[0] = 3.0;
174 chk_f.new_dynamic(p);
175 //
176 // set q in g(u; p, q)
177 q[0] = 4.0;
178 q[1] = 5.0;
179 g.new_dynamic(q);
180 //
181 // evalute g(u; p, q)
182 u[0] = 6.0;
183 u[1] = 7.0;
184 y = g.Forward(0, u);
185 //
186 // check value
187 ok &= y[0] == u[1] + q[1] + p[0] * (u[0] + q[0]);
188 // ------------------------------------------------------------------------
189 return ok;
190 }
191 // END C++
192