Я пытаюсь изменить пример здесь:
# include <cppad/cppad.hpp>
namespace { // ---------------------------------------------------------
// define the template function JacobianCases<Vector> in empty namespace
template <typename Vector>
bool JacobianCases()
{ bool ok = true;
using CppAD::AD;
using CppAD::NearEqual;
double eps99 = 99.0 * std::numeric_limits<double>::epsilon();
using CppAD::exp;
using CppAD::sin;
using CppAD::cos;
// domain space vector
size_t n = 2;
CPPAD_TESTVECTOR(AD<double>) X(n);
X[0] = 1.;
X[1] = 2.;
// declare independent variables and starting recording
CppAD::Independent(X);
// a calculation between the domain and range values
AD<double> Square = X[0] * X[0];
// range space vector
size_t m = 3;
CPPAD_TESTVECTOR(AD<double>) Y(m);
Y[0] = Square * exp( X[1] );
Y[1] = Square * sin( X[1] );
Y[2] = Square * cos( X[1] );
// create f: X -> Y and stop tape recording
CppAD::ADFun<double> f(X, Y);
// new value for the independent variable vector
Vector x(n);
x[0] = 2.;
x[1] = 1.;
// compute the derivative at this x
Vector jac( m * n );
jac = f.Jacobian(x);
/*
F'(x) = [ 2 * x[0] * exp(x[1]) , x[0] * x[0] * exp(x[1]) ]
[ 2 * x[0] * sin(x[1]) , x[0] * x[0] * cos(x[1]) ]
[ 2 * x[0] * cos(x[1]) , -x[0] * x[0] * sin(x[i]) ]
*/
ok &= NearEqual( 2.*x[0]*exp(x[1]), jac[0*n+0], eps99, eps99);
ok &= NearEqual( 2.*x[0]*sin(x[1]), jac[1*n+0], eps99, eps99);
ok &= NearEqual( 2.*x[0]*cos(x[1]), jac[2*n+0], eps99, eps99);
ok &= NearEqual( x[0] * x[0] *exp(x[1]), jac[0*n+1], eps99, eps99);
ok &= NearEqual( x[0] * x[0] *cos(x[1]), jac[1*n+1], eps99, eps99);
ok &= NearEqual(-x[0] * x[0] *sin(x[1]), jac[2*n+1], eps99, eps99);
return ok;
}
} // End empty namespace
# include <vector>
# include <valarray>
bool Jacobian(void)
{ bool ok = true;
// Run with Vector equal to three different cases
// all of which are Simple Vectors with elements of type double.
ok &= JacobianCases< CppAD::vector <double> >();
ok &= JacobianCases< std::vector <double> >();
ok &= JacobianCases< std::valarray <double> >();
return ok;
}
Я пытаюсь изменить его следующим образом:
Пусть G - якобианский jac
который вычисляется в этом примере в строке:
jac = f.Jacobian(x);
и, как и в примере, пусть X
- независимые переменные. Я хотел бы построить новую функцию H
, которая является функцией jac
, т. H(jacobian(X))
= что-то такое, что H автодифференцируемо. Примером может быть H(X) = jacobian( jacobian(X)[0])
, т.е. Якобиан первого элемента jacobian(X)
X
(вторая производная рода).
Проблема в том, что jac
как написано здесь, имеет тип Vector
, который является параметризованным типом на необработанном double
, а не AD<double>
. Насколько мне известно, это означает, что выход не является автодифференцируемым.
Я ищу несколько советов о том, можно ли использовать якобиан в более крупной операции и взять якобиан этой более крупной операции (в отличие от любого арифметического оператора), или если это невозможно.
РЕДАКТИРОВАТЬ: Это было выставлено на награду один раз, но я поднимаю его снова, чтобы увидеть, есть ли лучшее решение, потому что я думаю, что это важно. Чтобы быть более понятным, элементы, которые нужны "правильному" ответу:
а) Средство вычисления произвольных производных порядка.
б) разумный способ не указывать порядок производных априори. Если максимальная производная порядка должна быть известна во время компиляции, порядок производной не может быть определен алгоритмически. Кроме того, указание чрезвычайно большого порядка, как в текущем ответе, приведет к проблемам с распределением памяти и, я думаю, проблемам производительности.
c) Абстрагирование шаблона производного порядка от конечного пользователя. Это важно, потому что может быть сложно отслеживать порядок необходимых деривативов. Вероятно, это то, что приходит "бесплатно", если б) решается.
Если кто-то может взломать это, это будет потрясающий вклад и чрезвычайно полезная операция.