From: Alexei Sheplyakov Date: Sun, 29 May 2011 12:26:37 +0000 (+0300) Subject: Convert function.pl into C++ (well, almost) source and header. X-Git-Tag: release_1-6-3~64 X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=commitdiff_plain;h=a2314765ecb37b89ce5ab0d5491e58b6ac550b73 Convert function.pl into C++ (well, almost) source and header. The code is much more readable now, as it's (almost) plain C++ (except simple pythonic `preprocessor' instructions). As a side effect perl is no longer necessary for building GiNaC. --- diff --git a/configure.ac b/configure.ac index fc64c215..7ca6c3bb 100644 --- a/configure.ac +++ b/configure.ac @@ -101,6 +101,10 @@ dnl Check for stuff needed for building the GiNaC interactive shell (ginsh). AC_CHECK_HEADERS(unistd.h) GINAC_HAVE_RUSAGE GINAC_READLINE +dnl Python is necessary for building function.{cpp,h} +AC_PATH_PROG(PYTHON, python, "") +AS_IF([test -z "$PYTHON" -a ! -f "$srcdir/ginac/function.cpp"], + [AC_MSG_ERROR([GiNaC will not compile because Python is missing])]) dnl Check for dl library (needed for GiNaC::compile). GINAC_EXCOMPILER diff --git a/ginac/Makefile.am b/ginac/Makefile.am index dce098d5..8a3a7622 100644 --- a/ginac/Makefile.am +++ b/ginac/Makefile.am @@ -67,11 +67,13 @@ ginacinclude_HEADERS = ginac.h add.h archive.h assertion.h basic.h class_info.h parser/parser.h \ parser/parse_context.h -EXTRA_DIST = function.pl version.h.in +EXTRA_DIST = version.h.in function.hppy function.cppy -# Files which are generated by perl scripts -$(srcdir)/function.h $(srcdir)/function.cpp: $(srcdir)/function.pl - cd $(srcdir) && perl -w function.pl +BUILT_SOURCES = function.cpp function.h + +$(srcdir)/function.cpp: function.cppy function.py + $(PYTHON) $(srcdir)/function.py -o $@ $< + +$(srcdir)/function.h: function.hppy function.py + $(PYTHON) $(srcdir)/function.py -o $@ $< -# Force build of headers before compilation -$(srcdir)/add.cpp: $(srcdir)/function.h diff --git a/ginac/function.cppy b/ginac/function.cppy new file mode 100644 index 00000000..fb83cdc4 --- /dev/null +++ b/ginac/function.cppy @@ -0,0 +1,827 @@ +/** @file function.cpp + * + * Implementation of class of symbolic functions. */ + +/* + * This file was generated automatically by function.py. + * Please do not modify it directly, edit function.cppy instead! + * function.py options: maxargs=@maxargs@ + * + * GiNaC Copyright (C) 1999-2010 Johannes Gutenberg University Mainz, Germany + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "function.h" +#include "operators.h" +#include "fderivative.h" +#include "ex.h" +#include "lst.h" +#include "symmetry.h" +#include "print.h" +#include "power.h" +#include "archive.h" +#include "inifcns.h" +#include "tostring.h" +#include "utils.h" +#include "hash_seed.h" +#include "remember.h" + +#include +#include +#include +#include +#include + +namespace GiNaC { + +////////// +// helper class function_options +////////// + +function_options::function_options() +{ + initialize(); +} + +function_options::function_options(std::string const & n, std::string const & tn) +{ + initialize(); + set_name(n, tn); +} + +function_options::function_options(std::string const & n, unsigned np) +{ + initialize(); + set_name(n, std::string()); + nparams = np; +} + +function_options::~function_options() +{ + // nothing to clean up at the moment +} + +void function_options::initialize() +{ + set_name("unnamed_function", "\\\\mbox{unnamed}"); + nparams = 0; + eval_f = evalf_f = real_part_f = imag_part_f = conjugate_f = derivative_f + = power_f = series_f = 0; + evalf_params_first = true; + use_return_type = false; + eval_use_exvector_args = false; + evalf_use_exvector_args = false; + conjugate_use_exvector_args = false; + real_part_use_exvector_args = false; + imag_part_use_exvector_args = false; + derivative_use_exvector_args = false; + power_use_exvector_args = false; + series_use_exvector_args = false; + print_use_exvector_args = false; + use_remember = false; + functions_with_same_name = 1; + symtree = 0; +} + +function_options & function_options::set_name(std::string const & n, + std::string const & tn) +{ + name = n; + if (tn==std::string()) + 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 ++++ for method, N in [ (f, N) for f in methods[0:-1] for N in range(1, maxargs + 1)]: +function_options & function_options::@method@_func(@method@_funcp_@N@ e) +{ + test_and_set_nparams(@N@); + @method@_f = @method@_funcp(e); + return *this; +} +--- +// end of generated lines + ++++ for method in methods[0:-1]: +function_options & function_options::@method@_func(@method@_funcp_exvector e) +{ + @method@_use_exvector_args = true; + @method@_f = @method@_funcp(e); + return *this; +} +--- + +// end of generated lines + +function_options & function_options::set_return_type(unsigned rt, const return_type_t* rtt) +{ + use_return_type = true; + return_type = rt; + if (rtt != 0) + return_type_tinfo = *rtt; + else + return_type_tinfo = make_return_type_t(); + return *this; +} + +function_options & function_options::do_not_evalf_params() +{ + evalf_params_first = false; + return *this; +} + +function_options & function_options::remember(unsigned size, + unsigned assoc_size, + unsigned strategy) +{ + use_remember = true; + remember_size = size; + remember_assoc_size = assoc_size; + remember_strategy = strategy; + return *this; +} + +function_options & function_options::overloaded(unsigned o) +{ + 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) +{ + if (nparams==0) { + nparams = n; + } else if (nparams!=n) { + // we do not throw an exception here because this code is + // usually executed before main(), so the exception could not + // be caught anyhow + std::cerr << "WARNING: " << name << "(): number of parameters (" + << n << ") differs from number set before (" + << nparams << ")" << std::endl; + } +} + +void function_options::set_print_func(unsigned id, print_funcp f) +{ + if (id >= print_dispatch_table.size()) + print_dispatch_table.resize(id + 1); + print_dispatch_table[id] = f; +} + +/** This can be used as a hook for external applications. */ +unsigned function::current_serial = 0; + + +GINAC_IMPLEMENT_REGISTERED_CLASS(function, exprseq) + +////////// +// default constructor +////////// + +// public + +function::function() : serial(0) +{ +} + +////////// +// other constructors +////////// + +// public + +function::function(unsigned ser) : serial(ser) +{ +} + +// the following lines have been generated for max. @maxargs@ parameters ++++ for N in range(1, maxargs + 1): +function::function(unsigned ser, @seq('const ex & param%(n)d', N)@) + : exprseq(@seq('param%(n)d', N)@), serial(ser) +{ +} +--- + +function::function(unsigned ser, const exprseq & es) : exprseq(es), serial(ser) +{ + + // Force re-evaluation even if the exprseq was already evaluated + // (the exprseq copy constructor copies the flags) + clearflag(status_flags::evaluated); +} + +function::function(unsigned ser, const exvector & v, bool discardable) + : exprseq(v,discardable), serial(ser) +{ +} + +function::function(unsigned ser, std::auto_ptr vp) + : exprseq(vp), serial(ser) +{ +} + +////////// +// archiving +////////// + +/** Construct object from archive_node. */ +void function::read_archive(const archive_node& n, lst& sym_lst) +{ + inherited::read_archive(n, sym_lst); + // Find serial number by function name + std::string s; + if (n.find_string("name", s)) { + unsigned int ser = 0; + std::vector::const_iterator i = registered_functions().begin(), iend = registered_functions().end(); + while (i != iend) { + if (s == i->name) { + serial = ser; + return; + } + ++i; ++ser; + } + throw (std::runtime_error("unknown function '" + s + "' in archive")); + } else + throw (std::runtime_error("unnamed function in archive")); +} + +/** Archive the object. */ +void function::archive(archive_node &n) const +{ + inherited::archive(n); + GINAC_ASSERT(serial < registered_functions().size()); + n.add_string("name", registered_functions()[serial].name); +} + +GINAC_BIND_UNARCHIVER(function); + +////////// +// functions overriding virtual functions from base classes +////////// + +// public + +void function::print(const print_context & c, unsigned level) const +{ + GINAC_ASSERT(serial &pdt = opt.print_dispatch_table; + + // Dynamically dispatch on print_context type + const print_context_class_info *pc_info = &c.get_class_info(); + +next_context: + unsigned id = pc_info->options.get_id(); + if (id >= pdt.size() || pdt[id] == NULL) { + + // Method not found, try parent print_context class + const print_context_class_info *parent_pc_info = pc_info->get_parent(); + if (parent_pc_info) { + pc_info = parent_pc_info; + goto next_context; + } + + // Method still not found, use default output + if (is_a(c)) { + + c.s << std::string(level, ' ') << class_name() << " " + << opt.name << " @" << this + << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec + << ", nops=" << nops() + << std::endl; + unsigned delta_indent = static_cast(c).delta_indent; + for (size_t i=0; i(c)) { + + // Print function name in lowercase + std::string lname = opt.name; + size_t num = lname.size(); + for (size_t i=0; i(c)) { + c.s << opt.TeX_name; + printseq(c, '(', ',', ')', exprseq::precedence(), function::precedence()); + } else { + c.s << opt.name; + printseq(c, '(', ',', ')', exprseq::precedence(), function::precedence()); + } + + } else { + + // Method found, call it + current_serial = serial; + if (opt.print_use_exvector_args) + ((print_funcp_exvector)pdt[id])(seq, c); + else switch (opt.nparams) { + // the following lines have been generated for max. @maxargs@ parameters ++++ for N in range(1, maxargs + 1): + case @N@: + ((print_funcp_@N@)(pdt[id]))(@seq('seq[%(n)d]', N, 0)@, c); + break; +--- + // end of generated lines + default: + throw(std::logic_error("function::print(): invalid nparams")); + } + } +} + +ex function::expand(unsigned options) const +{ + // Only expand arguments when asked to do so + if (options & expand_options::expand_function_args) + return inherited::expand(options); + else + return (options == 0) ? setflag(status_flags::expanded) : *this; +} + +ex function::eval(int level) const +{ + if (level>1) { + // first evaluate children, then we will end up here again + return function(serial,evalchildren(level)); + } + + GINAC_ASSERT(serial 1 && !(opt.symtree.is_zero())) { + exvector v = seq; + GINAC_ASSERT(is_a(opt.symtree)); + int sig = canonicalize(v.begin(), ex_to(opt.symtree)); + if (sig != std::numeric_limits::max()) { + // Something has changed while sorting arguments, more evaluations later + if (sig == 0) + return _ex0; + return ex(sig) * thiscontainer(v); + } + } + + if (opt.eval_f==0) { + return this->hold(); + } + + bool use_remember = opt.use_remember; + ex eval_result; + if (use_remember && lookup_remember_table(eval_result)) { + return eval_result; + } + current_serial = serial; + if (opt.eval_use_exvector_args) + eval_result = ((eval_funcp_exvector)(opt.eval_f))(seq); + else + switch (opt.nparams) { + // the following lines have been generated for max. @maxargs@ parameters ++++ for N in range(1, maxargs + 1): + case @N@: + eval_result = ((eval_funcp_@N@)(opt.eval_f))(@seq('seq[%(n)d]', N, 0)@); + break; +--- + // end of generated lines + default: + throw(std::logic_error("function::eval(): invalid nparams")); + } + if (use_remember) { + store_remember_table(eval_result); + } + return eval_result; +} + +ex function::evalf(int level) const +{ + GINAC_ASSERT(serialevalf(level)); + ++it; + } + } + + if (opt.evalf_f==0) { + return function(serial,eseq).hold(); + } + current_serial = serial; + if (opt.evalf_use_exvector_args) + return ((evalf_funcp_exvector)(opt.evalf_f))(seq); + switch (opt.nparams) { + // the following lines have been generated for max. @maxargs@ parameters ++++ for N in range(1, maxargs + 1): + case @N@: + return ((evalf_funcp_@N@)(opt.evalf_f))(@seq('eseq[%(n)d]', N, 0)@); +--- + // end of generated lines + } + throw(std::logic_error("function::evalf(): invalid nparams")); +} + +/** + * This method is defined to be in line with behaviour of function::return_type() + */ +ex function::eval_ncmul(const exvector & v) const +{ + // If this function is called then the list of arguments is non-empty + // and the first argument is non-commutative, see function::return_type() + return seq.begin()->eval_ncmul(v); +} + +unsigned function::calchash() const +{ + unsigned v = golden_ratio_hash(make_hash_seed(typeid(*this)) ^ serial); + for (size_t i=0; iop(i).gethash(); + } + + if (flags & status_flags::evaluated) { + setflag(status_flags::hash_calculated); + hashvalue = v; + } + return v; +} + +ex function::thiscontainer(const exvector & v) const +{ + return function(serial, v); +} + +ex function::thiscontainer(std::auto_ptr vp) const +{ + return function(serial, vp); +} + +/** Implementation of ex::series for functions. + * \@see ex::series */ +ex function::series(const relational & r, int order, unsigned options) const +{ + GINAC_ASSERT(serial(other)); + const function & o = static_cast(other); + + if (serial != o.serial) + return serial < o.serial ? -1 : 1; + else + return exprseq::compare_same_type(o); +} + +bool function::is_equal_same_type(const basic & other) const +{ + GINAC_ASSERT(is_a(other)); + const function & o = static_cast(other); + + if (serial != o.serial) + return false; + else + return exprseq::is_equal_same_type(o); +} + +bool function::match_same_type(const basic & other) const +{ + GINAC_ASSERT(is_a(other)); + const function & o = static_cast(other); + + return serial == o.serial; +} + +unsigned function::return_type() const +{ + GINAC_ASSERT(serialreturn_type(); + } +} + +return_type_t function::return_type_tinfo() const +{ + GINAC_ASSERT(serial(); + else + return seq.begin()->return_type_tinfo(); + } +} + +////////// +// new virtual functions which can be overridden by derived classes +////////// + +// none + +////////// +// non-virtual functions in this class +////////// + +// protected + +ex function::pderivative(unsigned diff_param) const // partial differentiation +{ + GINAC_ASSERT(serialsetflag(status_flags::dynallocated | + status_flags::evaluated); + + current_serial = serial; + if (opt.power_use_exvector_args) + return ((power_funcp_exvector)(opt.power_f))(seq, power_param); + switch (opt.nparams) { + // the following lines have been generated for max. @maxargs@ parameters ++++ for N in range(1, maxargs + 1): + case @N@: + return ((power_funcp_@N@)(opt.power_f))(@seq('seq[%(n)d]', N, 0)@, power_param); +--- + // end of generated lines + } + throw(std::logic_error("function::power(): no power function defined")); +} + +std::vector & function::registered_functions() +{ + static std::vector rf = std::vector(); + return rf; +} + +bool function::lookup_remember_table(ex & result) const +{ + return remember_table::remember_tables()[this->serial].lookup_entry(*this,result); +} + +void function::store_remember_table(ex const & result) const +{ + remember_table::remember_tables()[this->serial].add_entry(*this,result); +} + +// public + +unsigned function::register_new(function_options const & opt) +{ + size_t same_name = 0; + for (size_t i=0; i=opt.functions_with_same_name) { + // we do not throw an exception here because this code is + // usually executed before main(), so the exception could not + // caught anyhow + std::cerr << "WARNING: function name " << opt.name + << " already in use!" << std::endl; + } + registered_functions().push_back(opt); + if (opt.use_remember) { + remember_table::remember_tables(). + push_back(remember_table(opt.remember_size, + opt.remember_assoc_size, + opt.remember_strategy)); + } else { + remember_table::remember_tables().push_back(remember_table()); + } + return registered_functions().size()-1; +} + +/** Find serial number of function by name and number of parameters. + * Throws exception if function was not found. */ +unsigned function::find_function(const std::string &name, unsigned nparams) +{ + std::vector::const_iterator i = function::registered_functions().begin(), end = function::registered_functions().end(); + unsigned serial = 0; + while (i != end) { + if (i->get_name() == name && i->get_nparams() == nparams) + return serial; + ++i; + ++serial; + } + throw (std::runtime_error("no function '" + name + "' with " + ToString(nparams) + " parameters defined")); +} + +/** Return the print name of the function. */ +std::string function::get_name() const +{ + GINAC_ASSERT(serial to work properly with +#include +#include +#include + ++++ for N in range(1, maxargs + 1): +#define DECLARE_FUNCTION_@N@P(NAME) \ +class NAME##_SERIAL { public: static unsigned serial; }; \ +const unsigned NAME##_NPARAMS = @N@; \ +template< @seq('typename T%(n)d', N)@ > const GiNaC::function NAME( @seq('const T%(n)d & p%(n)d', N)@ ) { \ + return GiNaC::function(NAME##_SERIAL::serial, @seq('GiNaC::ex(p%(n)d)', N)@ ); \ +} +--- +// end of generated lines + +#define REGISTER_FUNCTION(NAME,OPT) \ +unsigned NAME##_SERIAL::serial = \ + GiNaC::function::register_new(GiNaC::function_options(#NAME, NAME##_NPARAMS).OPT); + +namespace GiNaC { + +class function; +class symmetry; + +typedef ex (* eval_funcp)(); +typedef ex (* evalf_funcp)(); +typedef ex (* conjugate_funcp)(); +typedef ex (* real_part_funcp)(); +typedef ex (* imag_part_funcp)(); +typedef ex (* derivative_funcp)(); +typedef ex (* power_funcp)(); +typedef ex (* series_funcp)(); +typedef void (* print_funcp)(); + +// the following lines have been generated for max. @maxargs@ parameters ++++ for N, args in [ ( N, seq('const ex &', N) ) for N in range(1, maxargs + 1) ]: +typedef ex (* eval_funcp_@N@)( @args@ ); +typedef ex (* evalf_funcp_@N@)( @args@ ); +typedef ex (* conjugate_funcp_@N@)( @args@ ); +typedef ex (* real_part_funcp_@N@)( @args@ ); +typedef ex (* imag_part_funcp_@N@)( @args@ ); +typedef ex (* derivative_funcp_@N@)( @args@, unsigned ); +typedef ex (* power_funcp_@N@)( @args@, const ex & ); +typedef ex (* series_funcp_@N@)( @args@, const relational &, int, unsigned ); +typedef void (* print_funcp_@N@)( @args@, const print_context & ); +--- +// end of generated lines + +// Alternatively, an exvector may be passed into the static function, instead +// of individual ex objects. Then, the number of arguments is not limited. ++++ for fp in "eval evalf conjugate real_part imag_part".split(): +typedef ex (* @fp@_funcp_exvector)(const exvector &); +--- +typedef ex (* derivative_funcp_exvector)(const exvector &, unsigned); +typedef ex (* power_funcp_exvector)(const exvector &, const ex &); +typedef ex (* series_funcp_exvector)(const exvector &, const relational &, int, unsigned); +typedef void (* print_funcp_exvector)(const exvector &, const print_context &); + + +class function_options +{ + friend class function; + friend class fderivative; +public: + function_options(); + function_options(std::string const & n, std::string const & tn=std::string()); + function_options(std::string const & n, unsigned np); + ~function_options(); + void initialize(); + + function_options & dummy() { return *this; } + function_options & set_name(std::string const & n, std::string const & tn=std::string()); + function_options & latex_name(std::string const & tn); + // following lines have been generated for max. @maxargs@ parameters ++++ for f, N in [ (f, N) for f in methods[0:-1] for N in range(1, maxargs + 1) ]: + function_options & @f@_func(@f@_funcp_@N@ e); +--- ++++ for f in methods[0:-1]: + function_options & @f@_func(@f@_funcp_exvector e); +--- ++++ for N in range(1, N + 1): + template function_options & print_func(print_funcp_@N@ p) + { + test_and_set_nparams(@N@); + set_print_func(Ctx::get_class_info_static().options.get_id(), print_funcp(p)); + return *this; + } +--- + // end of generated lines + + template function_options & print_func(print_funcp_exvector p) + { + print_use_exvector_args = true; + set_print_func(Ctx::get_class_info_static().options.get_id(), print_funcp(p)); + return *this; + } + + function_options & set_return_type(unsigned rt, const return_type_t* rtt = 0); + function_options & do_not_evalf_params(); + 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); + + std::string get_name() const { return name; } + unsigned get_nparams() const { return nparams; } + +protected: + bool has_derivative() const { return derivative_f != NULL; } + bool has_power() const { return power_f != NULL; } + void test_and_set_nparams(unsigned n); + void set_print_func(unsigned id, print_funcp f); + + std::string name; + std::string TeX_name; + + unsigned nparams; + + eval_funcp eval_f; + evalf_funcp evalf_f; + conjugate_funcp conjugate_f; + real_part_funcp real_part_f; + imag_part_funcp imag_part_f; + derivative_funcp derivative_f; + power_funcp power_f; + series_funcp series_f; + std::vector print_dispatch_table; + + bool evalf_params_first; + + bool use_return_type; + unsigned return_type; + return_type_t return_type_tinfo; + + bool use_remember; + unsigned remember_size; + unsigned remember_assoc_size; + unsigned remember_strategy; + + bool eval_use_exvector_args; + bool evalf_use_exvector_args; + bool conjugate_use_exvector_args; + bool real_part_use_exvector_args; + bool imag_part_use_exvector_args; + bool derivative_use_exvector_args; + bool power_use_exvector_args; + bool series_use_exvector_args; + bool print_use_exvector_args; + + unsigned functions_with_same_name; + + ex symtree; +}; + + +/** Exception class thrown by classes which provide their own series expansion + * to signal that ordinary Taylor expansion is safe. */ +class do_taylor {}; + + +/** The class function is used to implement builtin functions like sin, cos... + and user defined functions */ +class function : public exprseq +{ + GINAC_DECLARE_REGISTERED_CLASS(function, exprseq) + + friend class remember_table_entry; + +// member functions + + // other constructors +public: + function(unsigned ser); + // the following lines have been generated for max. @maxargs@ parameters ++++ for N in range(1, maxargs + 1): + function(unsigned ser, @seq('const ex & param%(n)d', N)@); +--- + // end of generated lines + function(unsigned ser, const exprseq & es); + function(unsigned ser, const exvector & v, bool discardable = false); + function(unsigned ser, std::auto_ptr vp); + + // functions overriding virtual functions from base classes +public: + void print(const print_context & c, unsigned level = 0) const; + unsigned precedence() const {return 70;} + ex expand(unsigned options=0) const; + ex eval(int level=0) const; + ex evalf(int level=0) const; + ex eval_ncmul(const exvector & v) const; + unsigned calchash() const; + ex series(const relational & r, int order, unsigned options = 0) const; + ex thiscontainer(const exvector & v) const; + ex thiscontainer(std::auto_ptr vp) const; + ex conjugate() const; + ex real_part() const; + ex imag_part() const; + void archive(archive_node& n) const; + void read_archive(const archive_node& n, lst& syms); +protected: + ex derivative(const symbol & s) const; + bool is_equal_same_type(const basic & other) const; + bool match_same_type(const basic & other) const; + unsigned return_type() const; + return_type_t return_type_tinfo() const; + + // new virtual functions which can be overridden by derived classes + // none + + // non-virtual functions in this class +protected: + ex pderivative(unsigned diff_param) const; // partial differentiation + static std::vector & registered_functions(); + bool lookup_remember_table(ex & result) const; + void store_remember_table(ex const & result) const; +public: + ex power(const ex & exp) const; + static unsigned register_new(function_options const & opt); + static unsigned current_serial; + static unsigned find_function(const std::string &name, unsigned nparams); + static std::vector get_registered_functions() { return registered_functions(); }; + unsigned get_serial() const {return serial;} + std::string get_name() const; + +// member variables + +protected: + unsigned serial; +}; +GINAC_DECLARE_UNARCHIVER(function); + +// utility functions/macros + +template +inline bool is_the_function(const ex & x) +{ + return is_exactly_a(x) + && ex_to(x).get_serial() == T::serial; +} + +// Check whether OBJ is the specified symbolic function. +#define is_ex_the_function(OBJ, FUNCNAME) (GiNaC::is_the_function(OBJ)) + +} // namespace GiNaC + +#endif // ndef GINAC_FUNCTION_H + diff --git a/ginac/function.pl b/ginac/function.pl deleted file mode 100644 index d4a03cec..00000000 --- a/ginac/function.pl +++ /dev/null @@ -1,1416 +0,0 @@ -# This perl script automatically generates function.h and function.cpp - -# function.pl options: \$maxargs=${maxargs} -# -# GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -$maxargs=14; - -sub generate_seq { - my ($seq_template,$n)=@_; - my ($res,$N); - - $res=''; - for ($N=1; $N<=$n; $N++) { - $res .= eval('"' . $seq_template . '"'); - if ($N!=$n) { - $res .= ', '; - } - } - return $res; -} - -sub generate_from_to { - my ($template,$seq_template1,$seq_template2,$seq_template3,$from,$to)=@_; - my ($res,$N,$SEQ); - - $res=''; - for ($N=$from; $N<=$to; $N++) { - $SEQ1=generate_seq($seq_template1,$N); - $SEQ2=generate_seq($seq_template2,$N); - $SEQ3=generate_seq($seq_template3,$N); - $res .= eval('"' . $template . '"'); - $SEQ1=''; # to avoid main::SEQ1 used only once warning - $SEQ2=''; # same as above - $SEQ3=''; # same as above - } - return $res; -} - -sub generate { - my ($template,$seq_template1,$seq_template2,$seq_template3)=@_; - return generate_from_to($template,$seq_template1,$seq_template2,$seq_template3,1,$maxargs); -} - -$declare_function_macro = generate( - <<'END_OF_DECLARE_FUNCTION_MACRO','typename T${N}','const T${N} & p${N}','GiNaC::ex(p${N})'); -#define DECLARE_FUNCTION_${N}P(NAME) \\ -class NAME##_SERIAL { public: static unsigned serial; }; \\ -const unsigned NAME##_NPARAMS = ${N}; \\ -template<${SEQ1}> const GiNaC::function NAME(${SEQ2}) { \\ - return GiNaC::function(NAME##_SERIAL::serial, ${SEQ3}); \\ -} - -END_OF_DECLARE_FUNCTION_MACRO - -$typedef_eval_funcp=generate( -'typedef ex (* eval_funcp_${N})(${SEQ1});'."\n", -'const ex &','',''); - -$typedef_evalf_funcp=generate( -'typedef ex (* evalf_funcp_${N})(${SEQ1});'."\n", -'const ex &','',''); - -$typedef_conjugate_funcp=generate( -'typedef ex (* conjugate_funcp_${N})(${SEQ1});'."\n", -'const ex &','',''); - -$typedef_real_part_funcp=generate( -'typedef ex (* real_part_funcp_${N})(${SEQ1});'."\n", -'const ex &','',''); - -$typedef_imag_part_funcp=generate( -'typedef ex (* imag_part_funcp_${N})(${SEQ1});'."\n", -'const ex &','',''); - -$typedef_derivative_funcp=generate( -'typedef ex (* derivative_funcp_${N})(${SEQ1}, unsigned);'."\n", -'const ex &','',''); - -$typedef_power_funcp=generate( -'typedef ex (* power_funcp_${N})(${SEQ1}, const ex &);'."\n", -'const ex &','',''); - -$typedef_series_funcp=generate( -'typedef ex (* series_funcp_${N})(${SEQ1}, const relational &, int, unsigned);'."\n", -'const ex &','',''); - -$typedef_print_funcp=generate( -'typedef void (* print_funcp_${N})(${SEQ1}, const print_context &);'."\n", -'const ex &','',''); - -$eval_func_interface=generate(' function_options & eval_func(eval_funcp_${N} e);'."\n",'','',''); - -$evalf_func_interface=generate(' function_options & evalf_func(evalf_funcp_${N} ef);'."\n",'','',''); - -$conjugate_func_interface=generate(' function_options & conjugate_func(conjugate_funcp_${N} d);'."\n",'','',''); - -$real_part_func_interface=generate(' function_options & real_part_func(real_part_funcp_${N} d);'."\n",'','',''); - -$imag_part_func_interface=generate(' function_options & imag_part_func(imag_part_funcp_${N} d);'."\n",'','',''); - -$derivative_func_interface=generate(' function_options & derivative_func(derivative_funcp_${N} d);'."\n",'','',''); - -$power_func_interface=generate(' function_options & power_func(power_funcp_${N} d);'."\n",'','',''); - -$series_func_interface=generate(' function_options & series_func(series_funcp_${N} s);'."\n",'','',''); - -$print_func_interface=generate( - <<'END_OF_PRINT_FUNC_INTERFACE','','',''); - template function_options & print_func(print_funcp_${N} p) - { - test_and_set_nparams(${N}); - set_print_func(Ctx::get_class_info_static().options.get_id(), print_funcp(p)); - return *this; - } -END_OF_PRINT_FUNC_INTERFACE - -$constructors_interface=generate( -' function(unsigned ser, ${SEQ1});'."\n", -'const ex & param${N}','',''); - -$constructors_implementation=generate( - <<'END_OF_CONSTRUCTORS_IMPLEMENTATION','const ex & param${N}','param${N}',''); -function::function(unsigned ser, ${SEQ1}) - : exprseq(${SEQ2}), serial(ser) -{ -} -END_OF_CONSTRUCTORS_IMPLEMENTATION - -$eval_switch_statement=generate( - <<'END_OF_EVAL_SWITCH_STATEMENT','seq[${N}-1]','',''); - case ${N}: - eval_result = ((eval_funcp_${N})(opt.eval_f))(${SEQ1}); - break; -END_OF_EVAL_SWITCH_STATEMENT - -$evalf_switch_statement=generate( - <<'END_OF_EVALF_SWITCH_STATEMENT','eseq[${N}-1]','',''); - case ${N}: - return ((evalf_funcp_${N})(opt.evalf_f))(${SEQ1}); -END_OF_EVALF_SWITCH_STATEMENT - -$conjugate_switch_statement=generate( - <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','',''); - case ${N}: - return ((conjugate_funcp_${N})(opt.conjugate_f))(${SEQ1}); -END_OF_DIFF_SWITCH_STATEMENT - -$real_part_switch_statement=generate( - <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','',''); - case ${N}: - return ((real_part_funcp_${N})(opt.real_part_f))(${SEQ1}); -END_OF_DIFF_SWITCH_STATEMENT - -$imag_part_switch_statement=generate( - <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','',''); - case ${N}: - return ((imag_part_funcp_${N})(opt.imag_part_f))(${SEQ1}); -END_OF_DIFF_SWITCH_STATEMENT - -$diff_switch_statement=generate( - <<'END_OF_DIFF_SWITCH_STATEMENT','seq[${N}-1]','',''); - case ${N}: - return ((derivative_funcp_${N})(opt.derivative_f))(${SEQ1},diff_param); -END_OF_DIFF_SWITCH_STATEMENT - -$power_switch_statement=generate( - <<'END_OF_POWER_SWITCH_STATEMENT','seq[${N}-1]','',''); - case ${N}: - return ((power_funcp_${N})(opt.power_f))(${SEQ1},power_param); -END_OF_POWER_SWITCH_STATEMENT - -$series_switch_statement=generate( - <<'END_OF_SERIES_SWITCH_STATEMENT','seq[${N}-1]','',''); - case ${N}: - try { - res = ((series_funcp_${N})(opt.series_f))(${SEQ1},r,order,options); - } catch (do_taylor) { - res = basic::series(r, order, options); - } - return res; -END_OF_SERIES_SWITCH_STATEMENT - -$print_switch_statement=generate( - <<'END_OF_PRINT_SWITCH_STATEMENT','seq[${N}-1]','',''); - case ${N}: - ((print_funcp_${N})(pdt[id]))(${SEQ1}, c); - break; -END_OF_PRINT_SWITCH_STATEMENT - -$eval_func_implementation=generate( - <<'END_OF_EVAL_FUNC_IMPLEMENTATION','','',''); -function_options & function_options::eval_func(eval_funcp_${N} e) -{ - test_and_set_nparams(${N}); - eval_f = eval_funcp(e); - return *this; -} -END_OF_EVAL_FUNC_IMPLEMENTATION - -$evalf_func_implementation=generate( - <<'END_OF_EVALF_FUNC_IMPLEMENTATION','','',''); -function_options & function_options::evalf_func(evalf_funcp_${N} ef) -{ - test_and_set_nparams(${N}); - evalf_f = evalf_funcp(ef); - return *this; -} -END_OF_EVALF_FUNC_IMPLEMENTATION - -$conjugate_func_implementation=generate( - <<'END_OF_CONJUGATE_FUNC_IMPLEMENTATION','','',''); -function_options & function_options::conjugate_func(conjugate_funcp_${N} c) -{ - test_and_set_nparams(${N}); - conjugate_f = conjugate_funcp(c); - return *this; -} -END_OF_CONJUGATE_FUNC_IMPLEMENTATION - -$real_part_func_implementation=generate( - <<'END_OF_REAL_PART_FUNC_IMPLEMENTATION','','',''); -function_options & function_options::real_part_func(real_part_funcp_${N} c) -{ - test_and_set_nparams(${N}); - real_part_f = real_part_funcp(c); - return *this; -} -END_OF_REAL_PART_FUNC_IMPLEMENTATION - -$imag_part_func_implementation=generate( - <<'END_OF_IMAG_PART_FUNC_IMPLEMENTATION','','',''); -function_options & function_options::imag_part_func(imag_part_funcp_${N} c) -{ - test_and_set_nparams(${N}); - imag_part_f = imag_part_funcp(c); - return *this; -} -END_OF_IMAG_PART_FUNC_IMPLEMENTATION - -$derivative_func_implementation=generate( - <<'END_OF_DERIVATIVE_FUNC_IMPLEMENTATION','','',''); -function_options & function_options::derivative_func(derivative_funcp_${N} d) -{ - test_and_set_nparams(${N}); - derivative_f = derivative_funcp(d); - return *this; -} -END_OF_DERIVATIVE_FUNC_IMPLEMENTATION - -$power_func_implementation=generate( - <<'END_OF_POWER_FUNC_IMPLEMENTATION','','',''); -function_options & function_options::power_func(power_funcp_${N} d) -{ - test_and_set_nparams(${N}); - power_f = power_funcp(d); - return *this; -} -END_OF_POWER_FUNC_IMPLEMENTATION - -$series_func_implementation=generate( - <<'END_OF_SERIES_FUNC_IMPLEMENTATION','','',''); -function_options & function_options::series_func(series_funcp_${N} s) -{ - test_and_set_nparams(${N}); - series_f = series_funcp(s); - return *this; -} -END_OF_SERIES_FUNC_IMPLEMENTATION - -$interface=< to work properly with -#include -#include -#include - -// the following lines have been generated for max. ${maxargs} parameters -$declare_function_macro -// end of generated lines - -#define REGISTER_FUNCTION(NAME,OPT) \\ -unsigned NAME##_SERIAL::serial = \\ - GiNaC::function::register_new(GiNaC::function_options(#NAME, NAME##_NPARAMS).OPT); - -namespace GiNaC { - -class function; -class symmetry; - -typedef ex (* eval_funcp)(); -typedef ex (* evalf_funcp)(); -typedef ex (* conjugate_funcp)(); -typedef ex (* real_part_funcp)(); -typedef ex (* imag_part_funcp)(); -typedef ex (* derivative_funcp)(); -typedef ex (* power_funcp)(); -typedef ex (* series_funcp)(); -typedef void (* print_funcp)(); - -// the following lines have been generated for max. ${maxargs} parameters -$typedef_eval_funcp -$typedef_evalf_funcp -$typedef_conjugate_funcp -$typedef_real_part_funcp -$typedef_imag_part_funcp -$typedef_derivative_funcp -$typedef_power_funcp -$typedef_series_funcp -$typedef_print_funcp -// end of generated lines - -// Alternatively, an exvector may be passed into the static function, instead -// of individual ex objects. Then, the number of arguments is not limited. -typedef ex (* eval_funcp_exvector)(const exvector &); -typedef ex (* evalf_funcp_exvector)(const exvector &); -typedef ex (* conjugate_funcp_exvector)(const exvector &); -typedef ex (* real_part_funcp_exvector)(const exvector &); -typedef ex (* imag_part_funcp_exvector)(const exvector &); -typedef ex (* derivative_funcp_exvector)(const exvector &, unsigned); -typedef ex (* power_funcp_exvector)(const exvector &, const ex &); -typedef ex (* series_funcp_exvector)(const exvector &, const relational &, int, unsigned); -typedef void (* print_funcp_exvector)(const exvector &, const print_context &); - - -class function_options -{ - friend class function; - friend class fderivative; -public: - function_options(); - function_options(std::string const & n, std::string const & tn=std::string()); - function_options(std::string const & n, unsigned np); - ~function_options(); - void initialize(); - - function_options & dummy() { return *this; } - 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 -$conjugate_func_interface -$real_part_func_interface -$imag_part_func_interface -$derivative_func_interface -$power_func_interface -$series_func_interface -$print_func_interface -// end of generated lines - function_options & eval_func(eval_funcp_exvector e); - function_options & evalf_func(evalf_funcp_exvector ef); - function_options & conjugate_func(conjugate_funcp_exvector d); - function_options & real_part_func(real_part_funcp_exvector d); - function_options & imag_part_func(imag_part_funcp_exvector d); - function_options & derivative_func(derivative_funcp_exvector d); - function_options & power_func(power_funcp_exvector d); - function_options & series_func(series_funcp_exvector s); - - template function_options & print_func(print_funcp_exvector p) - { - print_use_exvector_args = true; - set_print_func(Ctx::get_class_info_static().options.get_id(), print_funcp(p)); - return *this; - } - - function_options & set_return_type(unsigned rt, const return_type_t* rtt = 0); - function_options & do_not_evalf_params(); - 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); - - std::string get_name() const { return name; } - unsigned get_nparams() const { return nparams; } - -protected: - bool has_derivative() const { return derivative_f != NULL; } - bool has_power() const { return power_f != NULL; } - void test_and_set_nparams(unsigned n); - void set_print_func(unsigned id, print_funcp f); - - std::string name; - std::string TeX_name; - - unsigned nparams; - - eval_funcp eval_f; - evalf_funcp evalf_f; - conjugate_funcp conjugate_f; - real_part_funcp real_part_f; - imag_part_funcp imag_part_f; - derivative_funcp derivative_f; - power_funcp power_f; - series_funcp series_f; - std::vector print_dispatch_table; - - bool evalf_params_first; - - bool use_return_type; - unsigned return_type; - return_type_t return_type_tinfo; - - bool use_remember; - unsigned remember_size; - unsigned remember_assoc_size; - unsigned remember_strategy; - - bool eval_use_exvector_args; - bool evalf_use_exvector_args; - bool conjugate_use_exvector_args; - bool real_part_use_exvector_args; - bool imag_part_use_exvector_args; - bool derivative_use_exvector_args; - bool power_use_exvector_args; - bool series_use_exvector_args; - bool print_use_exvector_args; - - unsigned functions_with_same_name; - - ex symtree; -}; - - -/** Exception class thrown by classes which provide their own series expansion - * to signal that ordinary Taylor expansion is safe. */ -class do_taylor {}; - - -/** The class function is used to implement builtin functions like sin, cos... - and user defined functions */ -class function : public exprseq -{ - GINAC_DECLARE_REGISTERED_CLASS(function, exprseq) - - // CINT has a linking problem -#ifndef __MAKECINT__ - friend void ginsh_get_ginac_functions(); -#endif // def __MAKECINT__ - - friend class remember_table_entry; - // friend class remember_table_list; - // friend class remember_table; - -// member functions - - // other constructors -public: - function(unsigned ser); - // the following lines have been generated for max. ${maxargs} parameters -$constructors_interface - // end of generated lines - function(unsigned ser, const exprseq & es); - function(unsigned ser, const exvector & v, bool discardable = false); - function(unsigned ser, std::auto_ptr vp); - - // functions overriding virtual functions from base classes -public: - void print(const print_context & c, unsigned level = 0) const; - unsigned precedence() const {return 70;} - ex expand(unsigned options=0) const; - ex eval(int level=0) const; - ex evalf(int level=0) const; - ex eval_ncmul(const exvector & v) const; - unsigned calchash() const; - ex series(const relational & r, int order, unsigned options = 0) const; - ex thiscontainer(const exvector & v) const; - ex thiscontainer(std::auto_ptr vp) const; - ex conjugate() const; - ex real_part() const; - ex imag_part() const; - void archive(archive_node& n) const; - void read_archive(const archive_node& n, lst& syms); -protected: - ex derivative(const symbol & s) const; - bool is_equal_same_type(const basic & other) const; - bool match_same_type(const basic & other) const; - unsigned return_type() const; - return_type_t return_type_tinfo() const; - - // new virtual functions which can be overridden by derived classes - // none - - // non-virtual functions in this class -protected: - ex pderivative(unsigned diff_param) const; // partial differentiation - static std::vector & registered_functions(); - bool lookup_remember_table(ex & result) const; - void store_remember_table(ex const & result) const; -public: - ex power(const ex & exp) const; - static unsigned register_new(function_options const & opt); - static unsigned current_serial; - static unsigned find_function(const std::string &name, unsigned nparams); - unsigned get_serial() const {return serial;} - std::string get_name() const; - -// member variables - -protected: - unsigned serial; -}; -GINAC_DECLARE_UNARCHIVER(function); - -// utility functions/macros - -template -inline bool is_the_function(const ex & x) -{ - return is_exactly_a(x) - && ex_to(x).get_serial() == T::serial; -} - -// Check whether OBJ is the specified symbolic function. -#define is_ex_the_function(OBJ, FUNCNAME) (GiNaC::is_the_function(OBJ)) - -} // namespace GiNaC - -#endif // ndef GINAC_FUNCTION_H - -END_OF_INTERFACE - -$implementation=< -#include -#include -#include -#include - -namespace GiNaC { - -////////// -// helper class function_options -////////// - -function_options::function_options() -{ - initialize(); -} - -function_options::function_options(std::string const & n, std::string const & tn) -{ - initialize(); - set_name(n, tn); -} - -function_options::function_options(std::string const & n, unsigned np) -{ - initialize(); - set_name(n, std::string()); - nparams = np; -} - -function_options::~function_options() -{ - // nothing to clean up at the moment -} - -void function_options::initialize() -{ - set_name("unnamed_function", "\\\\mbox{unnamed}"); - nparams = 0; - eval_f = evalf_f = real_part_f = imag_part_f = conjugate_f = derivative_f - = power_f = series_f = 0; - evalf_params_first = true; - use_return_type = false; - eval_use_exvector_args = false; - evalf_use_exvector_args = false; - conjugate_use_exvector_args = false; - real_part_use_exvector_args = false; - imag_part_use_exvector_args = false; - derivative_use_exvector_args = false; - power_use_exvector_args = false; - series_use_exvector_args = false; - print_use_exvector_args = false; - use_remember = false; - functions_with_same_name = 1; - symtree = 0; -} - -function_options & function_options::set_name(std::string const & n, - std::string const & tn) -{ - name = n; - if (tn==std::string()) - 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 -$conjugate_func_implementation -$real_part_func_implementation -$imag_part_func_implementation -$derivative_func_implementation -$power_func_implementation -$series_func_implementation -// end of generated lines - -function_options& function_options::eval_func(eval_funcp_exvector e) -{ - eval_use_exvector_args = true; - eval_f = eval_funcp(e); - return *this; -} -function_options& function_options::evalf_func(evalf_funcp_exvector ef) -{ - evalf_use_exvector_args = true; - evalf_f = evalf_funcp(ef); - return *this; -} -function_options& function_options::conjugate_func(conjugate_funcp_exvector c) -{ - conjugate_use_exvector_args = true; - conjugate_f = conjugate_funcp(c); - return *this; -} -function_options& function_options::real_part_func(real_part_funcp_exvector c) -{ - real_part_use_exvector_args = true; - real_part_f = real_part_funcp(c); - return *this; -} -function_options& function_options::imag_part_func(imag_part_funcp_exvector c) -{ - imag_part_use_exvector_args = true; - imag_part_f = imag_part_funcp(c); - return *this; -} - -function_options& function_options::derivative_func(derivative_funcp_exvector d) -{ - derivative_use_exvector_args = true; - derivative_f = derivative_funcp(d); - return *this; -} -function_options& function_options::power_func(power_funcp_exvector d) -{ - power_use_exvector_args = true; - power_f = power_funcp(d); - return *this; -} -function_options& function_options::series_func(series_funcp_exvector s) -{ - series_use_exvector_args = true; - series_f = series_funcp(s); - return *this; -} - -function_options & function_options::set_return_type(unsigned rt, const return_type_t* rtt) -{ - use_return_type = true; - return_type = rt; - if (rtt != 0) - return_type_tinfo = *rtt; - else - return_type_tinfo = make_return_type_t(); - return *this; -} - -function_options & function_options::do_not_evalf_params() -{ - evalf_params_first = false; - return *this; -} - -function_options & function_options::remember(unsigned size, - unsigned assoc_size, - unsigned strategy) -{ - use_remember = true; - remember_size = size; - remember_assoc_size = assoc_size; - remember_strategy = strategy; - return *this; -} - -function_options & function_options::overloaded(unsigned o) -{ - 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) -{ - if (nparams==0) { - nparams = n; - } else if (nparams!=n) { - // we do not throw an exception here because this code is - // usually executed before main(), so the exception could not - // be caught anyhow - std::cerr << "WARNING: " << name << "(): number of parameters (" - << n << ") differs from number set before (" - << nparams << ")" << std::endl; - } -} - -void function_options::set_print_func(unsigned id, print_funcp f) -{ - if (id >= print_dispatch_table.size()) - print_dispatch_table.resize(id + 1); - print_dispatch_table[id] = f; -} - -/** This can be used as a hook for external applications. */ -unsigned function::current_serial = 0; - - -GINAC_IMPLEMENT_REGISTERED_CLASS(function, exprseq) - -////////// -// default constructor -////////// - -// public - -function::function() : serial(0) -{ -} - -////////// -// other constructors -////////// - -// public - -function::function(unsigned ser) : serial(ser) -{ -} - -// the following lines have been generated for max. ${maxargs} parameters -$constructors_implementation -// end of generated lines - -function::function(unsigned ser, const exprseq & es) : exprseq(es), serial(ser) -{ - - // Force re-evaluation even if the exprseq was already evaluated - // (the exprseq copy constructor copies the flags) - clearflag(status_flags::evaluated); -} - -function::function(unsigned ser, const exvector & v, bool discardable) - : exprseq(v,discardable), serial(ser) -{ - if ( ser >= registered_functions().size() ) { - throw std::runtime_error("function does not exist"); - } -} - -function::function(unsigned ser, std::auto_ptr vp) - : exprseq(vp), serial(ser) -{ -} - -////////// -// archiving -////////// - -/** Construct object from archive_node. */ -void function::read_archive(const archive_node& n, lst& sym_lst) -{ - inherited::read_archive(n, sym_lst); - // Find serial number by function name - std::string s; - if (n.find_string("name", s)) { - unsigned int ser = 0; - std::vector::const_iterator i = registered_functions().begin(), iend = registered_functions().end(); - while (i != iend) { - if (s == i->name) { - serial = ser; - return; - } - ++i; ++ser; - } - throw (std::runtime_error("unknown function '" + s + "' in archive")); - } else - throw (std::runtime_error("unnamed function in archive")); -} - -/** Archive the object. */ -void function::archive(archive_node &n) const -{ - inherited::archive(n); - GINAC_ASSERT(serial < registered_functions().size()); - n.add_string("name", registered_functions()[serial].name); -} - -GINAC_BIND_UNARCHIVER(function); - -////////// -// functions overriding virtual functions from base classes -////////// - -// public - -void function::print(const print_context & c, unsigned level) const -{ - GINAC_ASSERT(serial &pdt = opt.print_dispatch_table; - - // Dynamically dispatch on print_context type - const print_context_class_info *pc_info = &c.get_class_info(); - -next_context: - unsigned id = pc_info->options.get_id(); - if (id >= pdt.size() || pdt[id] == NULL) { - - // Method not found, try parent print_context class - const print_context_class_info *parent_pc_info = pc_info->get_parent(); - if (parent_pc_info) { - pc_info = parent_pc_info; - goto next_context; - } - - // Method still not found, use default output - if (is_a(c)) { - - c.s << std::string(level, ' ') << class_name() << " " - << opt.name << " @" << this - << std::hex << ", hash=0x" << hashvalue << ", flags=0x" << flags << std::dec - << ", nops=" << nops() - << std::endl; - unsigned delta_indent = static_cast(c).delta_indent; - for (size_t i=0; i(c)) { - - // Print function name in lowercase - std::string lname = opt.name; - size_t num = lname.size(); - for (size_t i=0; i(c)) { - c.s << opt.TeX_name; - printseq(c, '(', ',', ')', exprseq::precedence(), function::precedence()); - } else { - c.s << opt.name; - printseq(c, '(', ',', ')', exprseq::precedence(), function::precedence()); - } - - } else { - - // Method found, call it - current_serial = serial; - if (opt.print_use_exvector_args) - ((print_funcp_exvector)pdt[id])(seq, c); - else switch (opt.nparams) { - // the following lines have been generated for max. ${maxargs} parameters -${print_switch_statement} - // end of generated lines - default: - throw(std::logic_error("function::print(): invalid nparams")); - } - } -} - -ex function::expand(unsigned options) const -{ - // Only expand arguments when asked to do so - if (options & expand_options::expand_function_args) - return inherited::expand(options); - else - return (options == 0) ? setflag(status_flags::expanded) : *this; -} - -ex function::eval(int level) const -{ - if (level>1) { - // first evaluate children, then we will end up here again - return function(serial,evalchildren(level)); - } - - GINAC_ASSERT(serial 1 && !(opt.symtree.is_zero())) { - exvector v = seq; - GINAC_ASSERT(is_a(opt.symtree)); - int sig = canonicalize(v.begin(), ex_to(opt.symtree)); - if (sig != std::numeric_limits::max()) { - // Something has changed while sorting arguments, more evaluations later - if (sig == 0) - return _ex0; - return ex(sig) * thiscontainer(v); - } - } - - if (opt.eval_f==0) { - return this->hold(); - } - - bool use_remember = opt.use_remember; - ex eval_result; - if (use_remember && lookup_remember_table(eval_result)) { - return eval_result; - } - current_serial = serial; - if (opt.eval_use_exvector_args) - eval_result = ((eval_funcp_exvector)(opt.eval_f))(seq); - else - switch (opt.nparams) { - // the following lines have been generated for max. ${maxargs} parameters -${eval_switch_statement} - // end of generated lines - default: - throw(std::logic_error("function::eval(): invalid nparams")); - } - if (use_remember) { - store_remember_table(eval_result); - } - return eval_result; -} - -ex function::evalf(int level) const -{ - GINAC_ASSERT(serialevalf(level)); - ++it; - } - } - - if (opt.evalf_f==0) { - return function(serial,eseq).hold(); - } - current_serial = serial; - if (opt.evalf_use_exvector_args) - return ((evalf_funcp_exvector)(opt.evalf_f))(seq); - switch (opt.nparams) { - // the following lines have been generated for max. ${maxargs} parameters -${evalf_switch_statement} - // end of generated lines - } - throw(std::logic_error("function::evalf(): invalid nparams")); -} - -/** - * This method is defined to be in line with behaviour of function::return_type() - */ -ex function::eval_ncmul(const exvector & v) const -{ - // If this function is called then the list of arguments is non-empty - // and the first argument is non-commutative, see function::return_type() - return seq.begin()->eval_ncmul(v); -} - -unsigned function::calchash() const -{ - unsigned v = golden_ratio_hash(make_hash_seed(typeid(*this)) ^ serial); - for (size_t i=0; iop(i).gethash(); - } - - if (flags & status_flags::evaluated) { - setflag(status_flags::hash_calculated); - hashvalue = v; - } - return v; -} - -ex function::thiscontainer(const exvector & v) const -{ - return function(serial, v); -} - -ex function::thiscontainer(std::auto_ptr vp) const -{ - return function(serial, vp); -} - -/** Implementation of ex::series for functions. - * \@see ex::series */ -ex function::series(const relational & r, int order, unsigned options) const -{ - GINAC_ASSERT(serial(other)); - const function & o = static_cast(other); - - if (serial != o.serial) - return serial < o.serial ? -1 : 1; - else - return exprseq::compare_same_type(o); -} - -bool function::is_equal_same_type(const basic & other) const -{ - GINAC_ASSERT(is_a(other)); - const function & o = static_cast(other); - - if (serial != o.serial) - return false; - else - return exprseq::is_equal_same_type(o); -} - -bool function::match_same_type(const basic & other) const -{ - GINAC_ASSERT(is_a(other)); - const function & o = static_cast(other); - - return serial == o.serial; -} - -unsigned function::return_type() const -{ - GINAC_ASSERT(serialreturn_type(); - } -} - -return_type_t function::return_type_tinfo() const -{ - GINAC_ASSERT(serial(); - else - return seq.begin()->return_type_tinfo(); - } -} - -////////// -// new virtual functions which can be overridden by derived classes -////////// - -// none - -////////// -// non-virtual functions in this class -////////// - -// protected - -ex function::pderivative(unsigned diff_param) const // partial differentiation -{ - GINAC_ASSERT(serialsetflag(status_flags::dynallocated | - status_flags::evaluated); - - current_serial = serial; - if (opt.power_use_exvector_args) - return ((power_funcp_exvector)(opt.power_f))(seq, power_param); - switch (opt.nparams) { - // the following lines have been generated for max. ${maxargs} parameters -${power_switch_statement} - // end of generated lines - } - throw(std::logic_error("function::power(): no power function defined")); -} - -std::vector & function::registered_functions() -{ - static std::vector rf = std::vector(); - return rf; -} - -bool function::lookup_remember_table(ex & result) const -{ - return remember_table::remember_tables()[this->serial].lookup_entry(*this,result); -} - -void function::store_remember_table(ex const & result) const -{ - remember_table::remember_tables()[this->serial].add_entry(*this,result); -} - -// public - -unsigned function::register_new(function_options const & opt) -{ - size_t same_name = 0; - for (size_t i=0; i=opt.functions_with_same_name) { - // we do not throw an exception here because this code is - // usually executed before main(), so the exception could not - // caught anyhow - std::cerr << "WARNING: function name " << opt.name - << " already in use!" << std::endl; - } - registered_functions().push_back(opt); - if (opt.use_remember) { - remember_table::remember_tables(). - push_back(remember_table(opt.remember_size, - opt.remember_assoc_size, - opt.remember_strategy)); - } else { - remember_table::remember_tables().push_back(remember_table()); - } - return registered_functions().size()-1; -} - -/** Find serial number of function by name and number of parameters. - * Throws exception if function was not found. */ -unsigned function::find_function(const std::string &name, unsigned nparams) -{ - std::vector::const_iterator i = function::registered_functions().begin(), end = function::registered_functions().end(); - unsigned serial = 0; - while (i != end) { - if (i->get_name() == name && i->get_nparams() == nparams) - return serial; - ++i; - ++serial; - } - throw (std::runtime_error("no function '" + name + "' with " + ToString(nparams) + " parameters defined")); -} - -/** Return the print name of the function. */ -std::string function::get_name() const -{ - if ( serial >= registered_functions().size() ) { - throw std::runtime_error("unknown function"); - } - return registered_functions()[serial].name; -} - -} // namespace GiNaC - -END_OF_IMPLEMENTATION - -print "Creating interface file function.h..."; -open OUT,">function.h" or die "cannot open function.h"; -print OUT $interface; -close OUT; -print "ok.\n"; - -print "Creating implementation file function.cpp..."; -open OUT,">function.cpp" or die "cannot open function.cpp"; -print OUT $implementation; -close OUT; -print "ok.\n"; - -print "done.\n"; diff --git a/ginac/function.py b/ginac/function.py new file mode 100755 index 00000000..6ceb2540 --- /dev/null +++ b/ginac/function.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# encoding: utf-8 + +maxargs = 14 +methods = "eval evalf conjugate real_part imag_part derivative power series print".split() + +import sys, os, optparse +sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'scripts')) +import yaptu + +def seq(template, N, start = 1, separator = ', '): + return separator.join([ template % { 'n' : n } for n in range(start, N + start) ]) + +def main(): + parser = optparse.OptionParser() + parser.add_option("-o", dest="outfile") + options, args = parser.parse_args() + cop = yaptu.copier(globals()) + if not options.outfile is None: + cop.ouf = open(options.outfile, 'wt') + inp = sys.stdin + if len(args) >= 1: + inp = open(args[0]) + cop.copy(inp) + if inp != sys.stdin: + inp.close() + if cop.ouf != sys.stdout: + cop.ouf.flush() + cop.ouf.close() + return 0 + +if __name__== '__main__': + ret = main() + sys.exit(ret) + diff --git a/ginsh/ginsh_parser.yy b/ginsh/ginsh_parser.yy index ab300a42..ead4f1f5 100644 --- a/ginsh/ginsh_parser.yy +++ b/ginsh/ginsh_parser.yy @@ -732,9 +732,10 @@ static ex f_ginac_function(const exprseq &es, int serial) // All registered GiNaC functions namespace GiNaC { -void ginsh_get_ginac_functions(void) +static void ginsh_get_ginac_functions(void) { - vector::const_iterator i = function::registered_functions().begin(), end = function::registered_functions().end(); + vector gfv = function::get_registered_functions(); + vector::const_iterator i = gfv.begin(), end = gfv.end(); unsigned serial = 0; while (i != end) { fcns.insert(make_pair(i->get_name(), fcn_desc(f_ginac_function, i->get_nparams(), serial))); diff --git a/scripts/yaptu.py b/scripts/yaptu.py new file mode 100644 index 00000000..ddf18f50 --- /dev/null +++ b/scripts/yaptu.py @@ -0,0 +1,93 @@ +#!/usr/bin/env python +""" +Yet Another Python Templating Utility, Version 1.2, by Alex Martelli. +Distributed under PSF license (http://docs.python.org/license.html). +""" + +import re +import sys + +# utility stuff to avoid tests in the mainline code +class _nevermatch: + "Polymorphic with a regex that never matches" + def match(self, line): + return None +_never = _nevermatch() # one reusable instance of it suffices +def identity(string, why): + "A do-nothing-special-to-the-input, just-return-it function" + return string +def nohandle(string): + "A do-nothing handler that just re-raises the exception" + raise + +_default_rex = re.compile('@([^@]+)@') +_default_rbe = re.compile('\+\+\+') +_default_ren = re.compile('---') +_default_rco = re.compile('===') + +# and now the real thing +class copier: + "Smart-copier (YAPTU) class" + def copyblock(self, i=0, last=None): + "Main copy method: process lines [i,last) of block" + def repl(match, self=self): + "return the eval of a found expression, for replacement" + # uncomment for debug: + # print '!!! replacing',match.group(1) + expr = self.preproc(match.group(1), 'eval') + try: return str(eval(expr, self.globals, self.locals)) + except: return str(self.handle(expr)) + block = self.locals['_bl'] + if last is None: last = len(block) + while i Executing: {"+stat+"}" + exec stat in self.globals,self.locals + i=j+1 + else: # normal line, just copy with substitution + self.ouf.write(self.regex.sub(repl,line)) + i=i+1 + def __init__(self, dict={}, regex=_default_rex, + restat=_default_rbe, restend=_default_ren, recont=_default_rco, + preproc=identity, handle=nohandle, ouf=sys.stdout): + "Initialize self's attributes" + self.regex = regex + self.globals = dict + self.locals = { '_cb':self.copyblock } + self.restat = restat + self.restend = restend + self.recont = recont + self.preproc = preproc + self.handle = handle + self.ouf = ouf + def copy(self, inf=sys.stdin, block=None): + "Entry point: copy-with-processing a file, or a block of lines" + if block is None: block = inf.readlines() + self.locals['_bl'] = block + self.copyblock() + +