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
|
// 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 graph_atom4_op.cpp}
C++ AD Graph Atomic Four Functions: Example and Test
####################################################
Source Code
***********
{xrst_literal
// BEGIN C++
// END C++
}
{xrst_end graph_atom4_op.cpp}
*/
// BEGIN C++
# include <cppad/cppad.hpp>
namespace {
class atomic_int_pow : public CppAD::atomic_four<double> {
public:
atomic_int_pow(void) : CppAD::atomic_four<double>("int_pow")
{ }
private:
// for_type
bool for_type(
size_t call_id ,
const CppAD::vector<CppAD::ad_type_enum>& type_x ,
CppAD::vector<CppAD::ad_type_enum>& type_y ) override
{ type_y[0] = type_x[0];
return true;
}
// forward
bool forward(
size_t call_id ,
const CppAD::vector<bool>& select_y ,
size_t order_low ,
size_t order_up ,
const CppAD::vector<double>& taylor_x ,
CppAD::vector<double>& taylor_y ) override
{
// order_up
if( order_up != 0 )
return false;
//
// taylor_y
taylor_y[0] = 1.0;
for(size_t i = 0; i < call_id; ++i)
taylor_y[0] *= taylor_x[0];
//
return true;
}
};
}
bool atom4_op(void)
{ bool ok = true;
using std::string;
//
// reciprocal
atomic_int_pow int_pow;
// -----------------------------------------------------------------------
//
// This function has an atomic function operator with name int_pow
// node_1 : p[0]
// node_2 : x[0]
// node_3 : p[0] + x[0]
// node_4 : int_pow( p[0] + x[0] )
// y[0] = ( p[0] + x[0] ) ** call_id
//
// call_id
size_t call_id = 2;
//
// C++ graph object
CppAD::cpp_graph graph_obj;
graph_obj.initialize();
//
// operator being used
CppAD::graph::graph_op_enum op_enum;
//
graph_obj.function_name_set("g(p; x)");
graph_obj.n_dynamic_ind_set(1);
graph_obj.n_variable_ind_set(1);
//
// node_3 : p[0] + x[0]
op_enum = CppAD::graph::add_graph_op;
graph_obj.operator_vec_push_back(op_enum);
graph_obj.operator_arg_push_back(1);
graph_obj.operator_arg_push_back(2);
//
// node_4 : f( p[0] + x[0] )
//
// name_index, n_result, n_arg come before first_node
size_t name_index = graph_obj.atomic_name_vec_size();
graph_obj.atomic_name_vec_push_back("int_pow");
//
op_enum = CppAD::graph::atom4_graph_op;
graph_obj.operator_vec_push_back(op_enum);
graph_obj.operator_arg_push_back(name_index); // name_index
graph_obj.operator_arg_push_back(call_id); // call_id
graph_obj.operator_arg_push_back(1); // n_result
graph_obj.operator_arg_push_back(1); // n_node_arg
graph_obj.operator_arg_push_back(3); // first and last node arg
//
// y[0] = int_pow( p[0] + x[0] ) = ( p[0] + x[0] ) ** call_id
graph_obj.dependent_vec_push_back(4);
// ------------------------------------------------------------------------
CppAD::ADFun<double> g;
g.from_graph(graph_obj);
// ------------------------------------------------------------------------
ok &= g.Domain() == 1;
ok &= g.Range() == 1;
ok &= g.size_dyn_ind() == 1;
//
// set p in g(p; x)
CPPAD_TESTVECTOR(double) p(1);
p[0] = 2.0;
g.new_dynamic(p);
//
// evaluate g(p; x)
CPPAD_TESTVECTOR(double) x(1), y(1);
x[0] = 3.0;
y = g.Forward(0, x);
//
// check value
double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
double check = std::pow( p[0] + x[0], double(call_id) );
ok &= CppAD::NearEqual(y[0], check, eps99, eps99);
// ------------------------------------------------------------------------
g.to_graph(graph_obj);
g.from_graph(graph_obj);
// ------------------------------------------------------------------------
ok &= g.Domain() == 1;
ok &= g.Range() == 1;
ok &= g.size_dyn_ind() == 1;
//
// set p in g(p; x)
p[0] = 4.0;
g.new_dynamic(p);
//
// evaluate g(p; x)
x[0] = 5.0;
y = g.Forward(0, x);
//
// check value
check = std::pow( p[0] + x[0], double(call_id) );
ok &= CppAD::NearEqual(y[0], check, eps99, eps99);
// ------------------------------------------------------------------------
return ok;
}
// END C++
|