const unsigned function_index_##NAME= \\
GiNaC::function::register_new(GiNaC::function_options(#NAME).OPT);
-#define REGISTER_FUNCTION_OLD(NAME,E,EF,D,S) \\
-const unsigned function_index_##NAME= \\
- GiNaC::function::register_new(GiNaC::function_options(#NAME). \\
- eval_func(E). \\
- evalf_func(EF). \\
- derivative_func(D). \\
- series_func(S));
-
#define BEGIN_TYPECHECK \\
bool automatic_typecheck=true;
#define TYPECHECK(VAR,TYPE) \\
-if (!is_ex_exactly_of_type(VAR,TYPE)) { \\
+if (!is_exactly_a<TYPE>(VAR)) { \\
automatic_typecheck=false; \\
} else
namespace GiNaC {
class function;
+class symmetry;
typedef ex (* eval_funcp)();
typedef ex (* evalf_funcp)();
~function_options();
void initialize(void);
function_options & set_name(std::string const & n, std::string const & tn=std::string());
+ function_options & latex_name(std::string const & tn);
// the following lines have been generated for max. ${maxargs} parameters
$eval_func_interface
$evalf_func_interface
function_options & remember(unsigned size, unsigned assoc_size=0,
unsigned strategy=remember_strategies::delete_never);
function_options & overloaded(unsigned o);
+ function_options & set_symmetry(const symmetry & s);
void test_and_set_nparams(unsigned n);
std::string get_name(void) const { return name; }
unsigned get_nparams(void) const { return nparams; }
unsigned remember_strategy;
unsigned functions_with_same_name;
+
+ ex symtree;
};
/** The class function is used to implement builtin functions like sin, cos...
// functions overriding virtual functions from bases classes
public:
void print(const print_context & c, unsigned level = 0) const;
+ unsigned precedence(void) const {return 70;}
int degree(const ex & s) const;
int ldegree(const ex & s) const;
ex coeff(const ex & s, int n = 1) const;
ex evalf(int level=0) const;
unsigned calchash(void) const;
ex series(const relational & r, int order, unsigned options = 0) const;
+ bool match(const ex & pattern, lst & repl_lst) const;
ex thisexprseq(const exvector & v) const;
ex thisexprseq(exvector * vp) const;
protected:
public:
static unsigned register_new(function_options const & opt);
static unsigned find_function(const std::string &name, unsigned nparams);
- unsigned getserial(void) const {return serial;}
+ unsigned get_serial(void) const {return serial;}
+ std::string get_name(void) const;
// member variables
};
// utility functions/macros
+/** Return the object of type function handled by an ex.
+ * This is unsafe: you need to check the type first. */
inline const function &ex_to_function(const ex &e)
{
return static_cast<const function &>(*e.bp);
}
+/** Specialization of is_exactly_a<function>(obj) for objects of type function. */
+template<> inline bool is_exactly_a<function>(const basic & obj)
+{
+ return obj.tinfo()==TINFO_function;
+}
+
#define is_ex_the_function(OBJ, FUNCNAME) \\
- (is_ex_exactly_of_type(OBJ, function) && static_cast<GiNaC::function *>(OBJ.bp)->getserial() == function_index_##FUNCNAME)
+ (is_ex_exactly_of_type(OBJ, function) && static_cast<GiNaC::function *>(OBJ.bp)->get_serial() == function_index_##FUNCNAME)
} // namespace GiNaC
#include "function.h"
#include "ex.h"
#include "lst.h"
+#include "symmetry.h"
#include "print.h"
#include "archive.h"
#include "inifcns.h"
void function_options::initialize(void)
{
- set_name("unnamed_function","\\\\operatorname{unnamed}");
+ set_name("unnamed_function","\\\\mbox{unnamed}");
nparams=0;
eval_f=evalf_f=derivative_f=series_f=0;
evalf_params_first=true;
use_return_type=false;
use_remember=false;
functions_with_same_name=1;
+ symtree = 0;
}
function_options & function_options::set_name(std::string const & n,
{
name=n;
if (tn==std::string()) {
- TeX_name="\\\\operatorname{"+name+"}";
+ TeX_name="\\\\mbox{"+name+"}";
} else {
TeX_name=tn;
}
return *this;
}
+function_options & function_options::latex_name(std::string const & tn)
+{
+ TeX_name=tn;
+ return *this;
+}
+
// the following lines have been generated for max. ${maxargs} parameters
$eval_func_implementation
$evalf_func_implementation
functions_with_same_name=o;
return *this;
}
+
+function_options & function_options::set_symmetry(const symmetry & s)
+{
+ symtree = s;
+ return *this;
+}
void function_options::test_and_set_nparams(unsigned n)
{
}
c.s << ")";
+ } else if (is_of_type(c, print_latex)) {
+ c.s << registered_functions()[serial].TeX_name;
+ printseq(c, '(', ',', ')', exprseq::precedence(), function::precedence());
} else {
c.s << registered_functions()[serial].name;
- printseq(c, '(', ',', ')', exprseq::precedence, function::precedence);
+ printseq(c, '(', ',', ')', exprseq::precedence(), function::precedence());
}
}
return function(serial,evalchildren(level));
}
- if (registered_functions()[serial].eval_f==0) {
+ const function_options &opt = registered_functions()[serial];
+
+ // Canonicalize argument order according to the symmetry properties
+ if (seq.size() > 1 && !(opt.symtree.is_zero())) {
+ exvector v = seq;
+ GINAC_ASSERT(is_ex_exactly_of_type(opt.symtree, symmetry));
+ int sig = canonicalize(v.begin(), ex_to<symmetry>(opt.symtree));
+ if (sig != INT_MAX) {
+ // Something has changed while sorting arguments, more evaluations later
+ if (sig == 0)
+ return _ex0();
+ return ex(sig) * thisexprseq(v);
+ }
+ }
+
+ if (opt.eval_f==0) {
return this->hold();
}
- bool use_remember=registered_functions()[serial].use_remember;
+ bool use_remember=opt.use_remember;
ex eval_result;
if (use_remember && lookup_remember_table(eval_result)) {
return eval_result;
}
- switch (registered_functions()[serial].nparams) {
+ switch (opt.nparams) {
// the following lines have been generated for max. ${maxargs} parameters
${eval_switch_statement}
// end of generated lines
throw(std::logic_error("function::series(): invalid nparams"));
}
+bool function::match(const ex & pattern, lst & repl_lst) const
+{
+ // Serial number must match
+ if (is_ex_of_type(pattern, function) && serial != ex_to<function>(pattern).serial)
+ return false;
+ return inherited::match(pattern, repl_lst);
+}
+
// protected
for (unsigned i=0; i!=fcn.nops(); i++) {
arg_diff = fcn.op(i).diff(s);
if (!arg_diff.is_zero()) {
- lst new_lst = ex_to_lst(seq[1]);
+ lst new_lst = ex_to<lst>(seq[1]);
new_lst.append(i);
result += arg_diff * Derivative(fcn, new_lst);
}
int function::compare_same_type(const basic & other) const
{
GINAC_ASSERT(is_of_type(other, function));
- const function & o=static_cast<function &>(const_cast<basic &>(other));
+ const function & o = static_cast<const function &>(other);
if (serial!=o.serial) {
return serial < o.serial ? -1 : 1;
bool function::is_equal_same_type(const basic & other) const
{
GINAC_ASSERT(is_of_type(other, function));
- const function & o=static_cast<function &>(const_cast<basic &>(other));
+ const function & o = static_cast<const function &>(other);
if (serial!=o.serial) return false;
return exprseq::is_equal_same_type(o);
throw (std::runtime_error("no function '" + name + "' with " + ToString(nparams) + " parameters defined"));
}
+/** Return the print name of the function. */
+std::string function::get_name(void) const
+{
+ GINAC_ASSERT(serial<registered_functions().size());
+ return registered_functions()[serial].name;
+}
+
} // namespace GiNaC
END_OF_IMPLEMENTATION