'typedef ex (* evalf_funcp_${N})(${SEQ1});'."\n",
'const ex &','');
-$typedef_diff_funcp=generate(
-'typedef ex (* diff_funcp_${N})(${SEQ1}, unsigned);'."\n",
+$typedef_derivative_funcp=generate(
+'typedef ex (* derivative_funcp_${N})(${SEQ1}, unsigned);'."\n",
'const ex &','');
$typedef_series_funcp=generate(
$register_new_interface=generate(
' static unsigned register_new(const char * nm, eval_funcp_${N} e,'."\n".
-' evalf_funcp_${N} ef=0, diff_funcp_${N} d=0, series_funcp_${N} s=0);'.
+' evalf_funcp_${N} ef=0, derivative_funcp_${N} d=0, series_funcp_${N} s=0);'.
"\n",'','');
$constructors_implementation=generate(
$diff_switch_statement=generate(
<<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','');
case ${N}:
- return ((diff_funcp_${N})(registered_functions()[serial].d))(${SEQ1},diff_param);
+ return ((derivative_funcp_${N})(registered_functions()[serial].d))(${SEQ1},diff_param);
break;
END_OF_DIFF_SWITCH_STATEMENT
$register_new_implementation=generate(
<<'END_OF_REGISTER_NEW_IMPLEMENTATION','','');
unsigned function::register_new(const char * nm, eval_funcp_${N} e,
- evalf_funcp_${N} ef, diff_funcp_${N} d, series_funcp_${N} s)
+ evalf_funcp_${N} ef, derivative_funcp_${N} d, series_funcp_${N} s)
{
registered_function_info rfi={nm,${N},0,eval_funcp(e),
- evalf_funcp(ef),diff_funcp(d),series_funcp(s)};
+ evalf_funcp(ef),derivative_funcp(d),series_funcp(s)};
registered_functions().push_back(rfi);
return registered_functions().size()-1;
}
#include "exprseq.h"
-#ifndef NO_GINAC_NAMESPACE
+#ifndef NO_NAMESPACE_GINAC
// the following lines have been generated for max. ${maxargs} parameters
$declare_function_macro_namespace
// end of generated lines
-#else // ndef NO_GINAC_NAMESPACE
+#else // ndef NO_NAMESPACE_GINAC
// the following lines have been generated for max. ${maxargs} parameters
$declare_function_macro_no_namespace
// end of generated lines
-#endif // ndef NO_GINAC_NAMESPACE
+#endif // ndef NO_NAMESPACE_GINAC
-#ifndef NO_GINAC_NAMESPACE
+#ifndef NO_NAMESPACE_GINAC
#define REGISTER_FUNCTION(NAME,E,EF,D,S) \\
const unsigned function_index_##NAME=GiNaC::function::register_new(#NAME,E,EF,D,S);
-#else // ndef NO_GINAC_NAMESPACE
+#else // ndef NO_NAMESPACE_GINAC
#define REGISTER_FUNCTION(NAME,E,EF,D,S) \\
const unsigned function_index_##NAME=function::register_new(#NAME,E,EF,D,S);
-#endif // ndef NO_GINAC_NAMESPACE
+#endif // ndef NO_NAMESPACE_GINAC
#define BEGIN_TYPECHECK \\
bool automatic_typecheck=true;
automatic_typecheck=false; \\
} else
-#ifndef NO_GINAC_NAMESPACE
+#ifndef NO_NAMESPACE_GINAC
#define TYPECHECK_INTEGER(VAR) \\
if (!(VAR).info(GiNaC::info_flags::integer)) { \\
automatic_typecheck=false; \\
} else
-#else // ndef NO_GINAC_NAMESPACE
+#else // ndef NO_NAMESPACE_GINAC
#define TYPECHECK_INTEGER(VAR) \\
if (!(VAR).info(info_flags::integer)) { \\
automatic_typecheck=false; \\
} else
-#endif // ndef NO_GINAC_NAMESPACE
+#endif // ndef NO_NAMESPACE_GINAC
#define END_TYPECHECK(RV) \\
{} \\
return RV.hold(); \\
}
-#ifndef NO_GINAC_NAMESPACE
+#ifndef NO_NAMESPACE_GINAC
namespace GiNaC {
-#endif // ndef NO_GINAC_NAMESPACE
+#endif // ndef NO_NAMESPACE_GINAC
class function;
typedef ex (* eval_funcp)();
typedef ex (* evalf_funcp)();
-typedef ex (* diff_funcp)();
+typedef ex (* derivative_funcp)();
typedef ex (* series_funcp)();
// the following lines have been generated for max. ${maxargs} parameters
$typedef_eval_funcp
$typedef_evalf_funcp
-$typedef_diff_funcp
+$typedef_derivative_funcp
$typedef_series_funcp
// end of generated lines
unsigned options;
eval_funcp e;
evalf_funcp ef;
- diff_funcp d;
+ derivative_funcp d;
series_funcp s;
};
ex expand(unsigned options=0) const;
ex eval(int level=0) const;
ex evalf(int level=0) const;
- ex diff(const symbol & s) const;
ex series(const symbol & s, const ex & point, int order) const;
ex thisexprseq(const exvector & v) const;
ex thisexprseq(exvector * vp) const;
protected:
+ ex derivative(const symbol & s) const;
int compare_same_type(const basic & other) const;
bool is_equal_same_type(const basic & other) const;
unsigned return_type(void) const;
// non-virtual functions in this class
protected:
- ex pdiff(unsigned diff_param) const; // partial differentiation
+ ex pderivative(unsigned diff_param) const; // partial differentiation
static vector<registered_function_info> & registered_functions(void);
public:
// the following lines have been generated for max. ${maxargs} parameters
// utility macros
-#ifndef NO_GINAC_NAMESPACE
+#ifndef NO_NAMESPACE_GINAC
#define is_ex_the_function(OBJ, FUNCNAME) \\
(is_ex_exactly_of_type(OBJ, function) && static_cast<GiNaC::function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
-#else // ndef NO_GINAC_NAMESPACE
+#else // ndef NO_NAMESPACE_GINAC
#define is_ex_the_function(OBJ, FUNCNAME) \\
(is_ex_exactly_of_type(OBJ, function) && static_cast<function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
-#endif // ndef NO_GINAC_NAMESPACE
+#endif // ndef NO_NAMESPACE_GINAC
// global constants
extern const function some_function;
extern const type_info & typeid_function;
-#ifndef NO_GINAC_NAMESPACE
+#ifndef NO_NAMESPACE_GINAC
} // namespace GiNaC
-#endif // ndef NO_GINAC_NAMESPACE
+#endif // ndef NO_NAMESPACE_GINAC
#endif // ndef __GINAC_FUNCTION_H__
#include "function.h"
#include "ex.h"
#include "archive.h"
+#include "inifcns.h"
#include "utils.h"
#include "debugmsg.h"
-#ifndef NO_GINAC_NAMESPACE
+#ifndef NO_NAMESPACE_GINAC
namespace GiNaC {
-#endif // ndef NO_GINAC_NAMESPACE
+#endif // ndef NO_NAMESPACE_GINAC
GINAC_IMPLEMENT_REGISTERED_CLASS(function, exprseq)
// protected
+
+/** Implementation of ex::diff() for functions. It applies the chain rule,
+ * except for the Order term function.
+ * \@see ex::diff */
+ex function::derivative(const symbol & s) const
+{
+ ex result;
+
+ if (serial==function_index_Order) {
+ // Order Term function only differentiates the argument
+ return Order(seq[0].diff(s));
+ } else {
+ // Chain rule
+ ex arg_diff;
+ for (unsigned i=0; i!=seq.size(); i++) {
+ arg_diff = seq[i].diff(s);
+ // We apply the chain rule only when it makes sense. This is not
+ // just for performance reasons but also to allow functions to
+ // throw when differentiated with respect to one of its arguments
+ // without running into trouble with our automatic full
+ // differentiation:
+ if (!arg_diff.is_zero())
+ result += pderivative(i)*arg_diff;
+ }
+ }
+ return result;
+}
+
int function::compare_same_type(const basic & other) const
{
GINAC_ASSERT(is_of_type(other, function));
// protected
-ex function::pdiff(unsigned diff_param) const // partial differentiation
+ex function::pderivative(unsigned diff_param) const // partial differentiation
{
GINAC_ASSERT(serial<registered_functions().size());
if (registered_functions()[serial].d==0) {
- throw(std::logic_error(string("function::pdiff(") + registered_functions()[serial].name + "): no diff function defined"));
+ throw(std::logic_error(string("function::pderivative(") + registered_functions()[serial].name + "): no diff function defined"));
}
switch (registered_functions()[serial].nparams) {
// the following lines have been generated for max. ${maxargs} parameters
${diff_switch_statement}
// end of generated lines
}
- throw(std::logic_error("function::pdiff(): no diff function defined"));
+ throw(std::logic_error("function::pderivative(): no diff function defined"));
}
vector<registered_function_info> & function::registered_functions(void)
const function some_function;
const type_info & typeid_function=typeid(some_function);
-#ifndef NO_GINAC_NAMESPACE
+#ifndef NO_NAMESPACE_GINAC
} // namespace GiNaC
-#endif // ndef NO_GINAC_NAMESPACE
+#endif // ndef NO_NAMESPACE_GINAC
END_OF_IMPLEMENTATION