PROPOSAL: Dynamic creation of functions

Pearu Peterson pearu at cens.ioc.ee
Mon Aug 20 18:56:54 CEST 2001



On Mon, 20 Aug 2001, Pearu Peterson wrote:

> What do you think? Can I can implement/test these modifications and send
> you them as a patch?

Meanwhile I implemented these hooks, and it works perfectly.
Please find the patch attached to this message.
To apply it, 'cd ginac/' and hit 'patch -p0 < function.pl.diff-0.9.3'.
As a result, I can now construct GiNaC functions directly in Python. Here
is an example of the corresponding Python session:

import ginac

class mysin:
  nparams = 1
  def eval(self, x):
    return self(x, hold=1)
  def derivative(self, x, diff_param):
    return ginac.cos(x)

f = ginac.build_function(mysin)
x = ginac.symbol('x')

print f(x)         # outputs: mysin(x)
print f(x).diff(x) # outputs: cos(x)

I hope that you find my patch useful for creating interfaces between GiNaC
and various scripting languages.

Regards,
	Pearu
-------------- next part --------------
--- function.pl.orig	Mon Aug 20 13:33:50 2001
+++ function.pl	Mon Aug 20 15:15:12 2001
@@ -239,6 +239,10 @@
 $typedef_derivative_funcp
 $typedef_series_funcp
 // end of generated lines
+typedef ex (* eval_funcp_v)(const exvector &);
+typedef ex (* evalf_funcp_v)(const exvector &);
+typedef ex (* derivative_funcp_v)(const exvector &, unsigned);
+typedef ex (* series_funcp_v)(const exvector &, const relational &, int, unsigned);
 
 class function_options
 {
@@ -257,6 +261,11 @@
 $derivative_func_interface
 $series_func_interface
 // end of generated lines
+        function_options& function_options::eval_func(eval_funcp_v e);
+        function_options& function_options::evalf_func(evalf_funcp_v ef);
+        function_options& function_options::derivative_func(derivative_funcp_v d);
+        function_options& function_options::series_func(series_funcp_v s);
+
 	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,
@@ -290,6 +299,11 @@
 	unsigned remember_assoc_size;
 	unsigned remember_strategy;
 
+        bool eval_use_vector_args;
+        bool evalf_use_vector_args;
+        bool derivative_use_vector_args;
+        bool series_use_vector_args;
+
 	unsigned functions_with_same_name;
 
 	ex symtree;
@@ -354,10 +368,10 @@
 	void store_remember_table(ex const & result) const;
 public:
 	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(void) const {return serial;}
 	std::string get_name(void) const;
-	
 // member variables
 
 protected:
@@ -433,6 +447,8 @@
 
 namespace GiNaC {
 
+unsigned function::current_serial = 0;
+
 //////////
 // helper class function_options
 //////////
@@ -461,6 +477,10 @@
 	evalf_params_first = true;
 	use_return_type = false;
 	use_remember = false;
+        eval_use_vector_args = false;
+        evalf_use_vector_args = false;
+        derivative_use_vector_args = false;
+        series_use_vector_args = false;
 	functions_with_same_name = 1;
 	symtree = 0;
 }
@@ -488,6 +508,30 @@
 $derivative_func_implementation
 $series_func_implementation
 // end of generated lines
+function_options& function_options::eval_func(eval_funcp_v e)
+{
+        eval_use_vector_args = true;
+        eval_f = eval_funcp(e);
+        return *this;
+}
+function_options& function_options::evalf_func(evalf_funcp_v ef)
+{
+        evalf_use_vector_args = true;
+        evalf_f = evalf_funcp(ef);
+        return *this;
+}
+function_options& function_options::derivative_func(derivative_funcp_v d)
+{
+        derivative_use_vector_args = true;
+        derivative_f = derivative_funcp(d);
+        return *this;
+}
+function_options& function_options::series_func(series_funcp_v s)
+{
+        series_use_vector_args = true;
+        series_f = series_funcp(s);
+        return *this;
+}
 
 function_options & function_options::set_return_type(unsigned rt, unsigned rtt)
 {
@@ -756,7 +800,11 @@
 	if (use_remember && lookup_remember_table(eval_result)) {
 		return eval_result;
 	}
-
+        current_serial = serial;
+        if (registered_functions()[serial].eval_use_vector_args) {
+		eval_result = ((eval_funcp_v)(registered_functions()[serial].eval_f))(seq);
+	}
+	else
 	switch (opt.nparams) {
 		// the following lines have been generated for max. ${maxargs} parameters
 ${eval_switch_statement}
@@ -792,6 +840,9 @@
 	if (registered_functions()[serial].evalf_f==0) {
 		return function(serial,eseq).hold();
 	}
+        current_serial = serial;
+        if (registered_functions()[serial].evalf_use_vector_args)
+		return ((evalf_funcp_v)(registered_functions()[serial].evalf_f))(seq);
 	switch (registered_functions()[serial].nparams) {
 		// the following lines have been generated for max. ${maxargs} parameters
 ${evalf_switch_statement}
@@ -835,6 +886,15 @@
 		return basic::series(r, order);
 	}
 	ex res;
+        current_serial = serial;
+        if (registered_functions()[serial].series_use_vector_args) {
+	    try {
+		res = ((series_funcp_v)(registered_functions()[serial].series_f))(seq, r, order, options);
+	    } catch (do_taylor) {
+		res = basic::series(r, order, options);
+	    }
+            return res;
+	}
 	switch (registered_functions()[serial].nparams) {
 		// the following lines have been generated for max. ${maxargs} parameters
 ${series_switch_statement}
@@ -938,7 +998,9 @@
 	// No derivative defined? Then return abstract derivative object
 	if (registered_functions()[serial].derivative_f == NULL)
 		return fderivative(serial, diff_param, seq);
-
+        current_serial = serial;
+        if (registered_functions()[serial].derivative_use_vector_args)
+		return ((derivative_funcp_v)(registered_functions()[serial].derivative_f))(seq, diff_param);
 	switch (registered_functions()[serial].nparams) {
 		// the following lines have been generated for max. ${maxargs} parameters
 ${diff_switch_statement}


More information about the GiNaC-devel mailing list