/** @file function.h
 *
 *  Interface to abstract class function (new function concept). */

/*
 *  This file was generated automatically by function.pl.
 *  Please do not modify it directly, edit the perl script instead!
 *  function.pl options: $maxargs=13
 *
 *  GiNaC Copyright (C) 1999-2001 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#ifndef __GINAC_FUNCTION_H__
#define __GINAC_FUNCTION_H__

#include <string>
#include <vector>

// CINT needs <algorithm> to work properly with <vector> 
#include <algorithm>

#include "exprseq.h"

// the following lines have been generated for max. 13 parameters
#define DECLARE_FUNCTION_1P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1) { \
	return GiNaC::function(function_index_##NAME, p1); \
}
#define DECLARE_FUNCTION_2P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2) { \
	return GiNaC::function(function_index_##NAME, p1, p2); \
}

#define DECLARE_FUNCTION_3P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3); \
}

#define DECLARE_FUNCTION_4P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4); \
}

#define DECLARE_FUNCTION_5P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4, const GiNaC::ex & p5) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4, p5); \
}

#define DECLARE_FUNCTION_6P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4, const GiNaC::ex & p5, const GiNaC::ex & p6) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4, p5, p6); \
}

#define DECLARE_FUNCTION_7P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4, const GiNaC::ex & p5, const GiNaC::ex & p6, const GiNaC::ex & p7) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7); \
}

#define DECLARE_FUNCTION_8P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4, const GiNaC::ex & p5, const GiNaC::ex & p6, const GiNaC::ex & p7, const GiNaC::ex & p8) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7, p8); \
}

#define DECLARE_FUNCTION_9P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4, const GiNaC::ex & p5, const GiNaC::ex & p6, const GiNaC::ex & p7, const GiNaC::ex & p8, const GiNaC::ex & p9) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7, p8, p9); \
}

#define DECLARE_FUNCTION_10P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4, const GiNaC::ex & p5, const GiNaC::ex & p6, const GiNaC::ex & p7, const GiNaC::ex & p8, const GiNaC::ex & p9, const GiNaC::ex & p10) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); \
}

#define DECLARE_FUNCTION_11P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4, const GiNaC::ex & p5, const GiNaC::ex & p6, const GiNaC::ex & p7, const GiNaC::ex & p8, const GiNaC::ex & p9, const GiNaC::ex & p10, const GiNaC::ex & p11) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); \
}

#define DECLARE_FUNCTION_12P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4, const GiNaC::ex & p5, const GiNaC::ex & p6, const GiNaC::ex & p7, const GiNaC::ex & p8, const GiNaC::ex & p9, const GiNaC::ex & p10, const GiNaC::ex & p11, const GiNaC::ex & p12) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); \
}

#define DECLARE_FUNCTION_13P(NAME) \
extern const unsigned function_index_##NAME; \
inline GiNaC::function NAME(const GiNaC::ex & p1, const GiNaC::ex & p2, const GiNaC::ex & p3, const GiNaC::ex & p4, const GiNaC::ex & p5, const GiNaC::ex & p6, const GiNaC::ex & p7, const GiNaC::ex & p8, const GiNaC::ex & p9, const GiNaC::ex & p10, const GiNaC::ex & p11, const GiNaC::ex & p12, const GiNaC::ex & p13) { \
	return GiNaC::function(function_index_##NAME, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); \
}


// end of generated lines

#define REGISTER_FUNCTION(NAME,OPT) \
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)) { \
	automatic_typecheck=false; \
} else

#define TYPECHECK_INTEGER(VAR) \
if (!(VAR).info(GiNaC::info_flags::integer)) { \
	automatic_typecheck=false; \
} else

#define END_TYPECHECK(RV) \
{} \
if (!automatic_typecheck) { \
	return RV.hold(); \
}

namespace GiNaC {

class function;

typedef ex (* eval_funcp)();
typedef ex (* evalf_funcp)();
typedef ex (* derivative_funcp)();
typedef ex (* series_funcp)();

// the following lines have been generated for max. 13 parameters
typedef ex (* eval_funcp_1)(const ex &);
typedef ex (* eval_funcp_2)(const ex &, const ex &);
typedef ex (* eval_funcp_3)(const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_4)(const ex &, const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_5)(const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_6)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_7)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_8)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_9)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_10)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_11)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_12)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* eval_funcp_13)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);

typedef ex (* evalf_funcp_1)(const ex &);
typedef ex (* evalf_funcp_2)(const ex &, const ex &);
typedef ex (* evalf_funcp_3)(const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_4)(const ex &, const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_5)(const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_6)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_7)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_8)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_9)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_10)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_11)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_12)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);
typedef ex (* evalf_funcp_13)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &);

typedef ex (* derivative_funcp_1)(const ex &, unsigned);
typedef ex (* derivative_funcp_2)(const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_3)(const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_4)(const ex &, const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_5)(const ex &, const ex &, const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_6)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_7)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_8)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_9)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_10)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_11)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_12)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, unsigned);
typedef ex (* derivative_funcp_13)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, unsigned);

typedef ex (* series_funcp_1)(const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_2)(const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_3)(const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_4)(const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_5)(const ex &, const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_6)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_7)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_8)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_9)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_10)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_11)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_12)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);
typedef ex (* series_funcp_13)(const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const ex &, const relational &, int, unsigned);

// end of generated lines

class function_options
{
	friend class function;
public:
	function_options();
	function_options(std::string const & n, std::string const & tn=std::string());
	~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. 13 parameters
    function_options & eval_func(eval_funcp_1 e);
    function_options & eval_func(eval_funcp_2 e);
    function_options & eval_func(eval_funcp_3 e);
    function_options & eval_func(eval_funcp_4 e);
    function_options & eval_func(eval_funcp_5 e);
    function_options & eval_func(eval_funcp_6 e);
    function_options & eval_func(eval_funcp_7 e);
    function_options & eval_func(eval_funcp_8 e);
    function_options & eval_func(eval_funcp_9 e);
    function_options & eval_func(eval_funcp_10 e);
    function_options & eval_func(eval_funcp_11 e);
    function_options & eval_func(eval_funcp_12 e);
    function_options & eval_func(eval_funcp_13 e);

    function_options & evalf_func(evalf_funcp_1 ef);
    function_options & evalf_func(evalf_funcp_2 ef);
    function_options & evalf_func(evalf_funcp_3 ef);
    function_options & evalf_func(evalf_funcp_4 ef);
    function_options & evalf_func(evalf_funcp_5 ef);
    function_options & evalf_func(evalf_funcp_6 ef);
    function_options & evalf_func(evalf_funcp_7 ef);
    function_options & evalf_func(evalf_funcp_8 ef);
    function_options & evalf_func(evalf_funcp_9 ef);
    function_options & evalf_func(evalf_funcp_10 ef);
    function_options & evalf_func(evalf_funcp_11 ef);
    function_options & evalf_func(evalf_funcp_12 ef);
    function_options & evalf_func(evalf_funcp_13 ef);

    function_options & derivative_func(derivative_funcp_1 d);
    function_options & derivative_func(derivative_funcp_2 d);
    function_options & derivative_func(derivative_funcp_3 d);
    function_options & derivative_func(derivative_funcp_4 d);
    function_options & derivative_func(derivative_funcp_5 d);
    function_options & derivative_func(derivative_funcp_6 d);
    function_options & derivative_func(derivative_funcp_7 d);
    function_options & derivative_func(derivative_funcp_8 d);
    function_options & derivative_func(derivative_funcp_9 d);
    function_options & derivative_func(derivative_funcp_10 d);
    function_options & derivative_func(derivative_funcp_11 d);
    function_options & derivative_func(derivative_funcp_12 d);
    function_options & derivative_func(derivative_funcp_13 d);

    function_options & series_func(series_funcp_1 s);
    function_options & series_func(series_funcp_2 s);
    function_options & series_func(series_funcp_3 s);
    function_options & series_func(series_funcp_4 s);
    function_options & series_func(series_funcp_5 s);
    function_options & series_func(series_funcp_6 s);
    function_options & series_func(series_funcp_7 s);
    function_options & series_func(series_funcp_8 s);
    function_options & series_func(series_funcp_9 s);
    function_options & series_func(series_funcp_10 s);
    function_options & series_func(series_funcp_11 s);
    function_options & series_func(series_funcp_12 s);
    function_options & series_func(series_funcp_13 s);

// end of generated lines
	function_options & set_return_type(unsigned rt, unsigned rtt=0);
	function_options & do_not_evalf_params(void);
	function_options & remember(unsigned size, unsigned assoc_size=0,
	                            unsigned strategy=remember_strategies::delete_never);
	function_options & overloaded(unsigned o);
	void test_and_set_nparams(unsigned n);
	std::string get_name(void) const { return name; }
	unsigned get_nparams(void) const { return nparams; }

protected:
	std::string name;
	std::string TeX_name;

	unsigned nparams;

	eval_funcp eval_f;
	evalf_funcp evalf_f;
	derivative_funcp derivative_f;
	series_funcp series_f;

	bool evalf_params_first;

	bool use_return_type;
	unsigned return_type;
	unsigned return_type_tinfo;

	bool use_remember;
	unsigned remember_size;
	unsigned remember_assoc_size;
	unsigned remember_strategy;

	unsigned functions_with_same_name;
};

/** 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(void);
#endif // def __MAKECINT__

	friend class remember_table_entry;
	// friend class remember_table_list;
	// friend class remember_table;

// member functions

	// other ctors
public:
	function(unsigned ser);
	// the following lines have been generated for max. 13 parameters
    function(unsigned ser, const ex & param1);
    function(unsigned ser, const ex & param1, const ex & param2);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4, const ex & param5);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4, const ex & param5, const ex & param6);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4, const ex & param5, const ex & param6, const ex & param7);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4, const ex & param5, const ex & param6, const ex & param7, const ex & param8);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4, const ex & param5, const ex & param6, const ex & param7, const ex & param8, const ex & param9);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4, const ex & param5, const ex & param6, const ex & param7, const ex & param8, const ex & param9, const ex & param10);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4, const ex & param5, const ex & param6, const ex & param7, const ex & param8, const ex & param9, const ex & param10, const ex & param11);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4, const ex & param5, const ex & param6, const ex & param7, const ex & param8, const ex & param9, const ex & param10, const ex & param11, const ex & param12);
    function(unsigned ser, const ex & param1, const ex & param2, const ex & param3, const ex & param4, const ex & param5, const ex & param6, const ex & param7, const ex & param8, const ex & param9, const ex & param10, const ex & param11, const ex & param12, const ex & param13);

	// end of generated lines
	function(unsigned ser, const exprseq & es);
	function(unsigned ser, const exvector & v, bool discardable=0);
	function(unsigned ser, exvector * vp); // vp will be deleted

	// functions overriding virtual functions from bases classes
public:
	void print(const print_context & c, unsigned level = 0) const;
	int degree(const ex & s) const;
	int ldegree(const ex & s) const;
	ex coeff(const ex & s, int n = 1) const;
	ex expand(unsigned options=0) const;
	ex eval(int level=0) const;
	ex evalf(int level=0) const;
	unsigned calchash(void) const;
	ex series(const relational & r, int order, unsigned options = 0) const;
	ex thisexprseq(const exvector & v) const;
	ex thisexprseq(exvector * vp) const;
protected:
	ex derivative(const symbol & s) const;
	bool is_equal_same_type(const basic & other) const;
	unsigned return_type(void) const;
	unsigned return_type_tinfo(void) 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<function_options> & registered_functions(void);
	bool lookup_remember_table(ex & result) const;
	void store_remember_table(ex const & result) const;
public:
	static unsigned register_new(function_options const & opt);
	static unsigned find_function(const std::string &name, unsigned nparams);
	unsigned get_serial(void) const {return serial;}
	std::string get_name(void) const;
	
// member variables

protected:
	unsigned serial;
};

// utility functions/macros
inline const function &ex_to_function(const ex &e)
{
	return static_cast<const function &>(*e.bp);
}

#define is_ex_the_function(OBJ, FUNCNAME) \
	(is_ex_exactly_of_type(OBJ, function) && static_cast<GiNaC::function *>(OBJ.bp)->get_serial() == function_index_##FUNCNAME)

} // namespace GiNaC

#endif // ndef __GINAC_FUNCTION_H__

