# HG changeset patch
# User Burcin Erocal
# Date 1319973071 3600
# Node ID ea60adae7e78a92592fd03fb707908e2c851de69
# Parent d740726a92bc0eef8e372e0a59c37b6cdf0a84b0
Create fast numeric evaluation path for special functions.
Most Sage types define methods for numeric special function evaluation. The
GinacFunction class defines a __call__() method to utilize these methods when
they exists. Moving the definition of this __call__() method up one level in
the inheritance diagram to BuiltinFunction allows more symbolic functions to
take advantage of this optimization.
diff git a/sage/symbolic/function.pyx b/sage/symbolic/function.pyx
 a/sage/symbolic/function.pyx
+++ b/sage/symbolic/function.pyx
@@ 689,62 +689,6 @@
g_foptions_assign(g_registered_functions().index(self._serial), opt)
 def __call__(self, *args, coerce=True, hold=False,
 dont_call_method_on_arg=False):
 """
 Evaluate this function on the given arguments and return the result.

 EXAMPLES::

 sage: exp(5)
 e^5
 sage: gamma(15)
 87178291200
 """
 # we want to convert the result to the original parent if the input
 # is not exact, so we store the parent here
 org_parent = parent_c(args[0])

 # if there is only one argument, and the argument has an attribute
 # with the same name as this function, try to call it to get the result
 # The argument dont_call_method_on_arg is used to prevent infinite loops
 # when .exp(), .log(), etc. methods call this symbolic function on
 # themselves
 if len(args) == 1 and not hold and not dont_call_method_on_arg and \
 hasattr(args[0], self._name):
 return getattr(args[0], self._name)()

 res = super(GinacFunction, self).__call__(*args, coerce=coerce,
 hold=hold)

 # convert the result back to the original parent previously stored
 # otherwise we end up with
 # sage: arctan(RR(1))
 # 1/4*pi
 # which is surprising, to say the least...
 if org_parent is not SR and \
 (org_parent is float or org_parent is complex or \
 (PY_TYPE_CHECK(org_parent, Parent) and \
 not org_parent.is_exact())):
 try:
 return org_parent(res)
 except (TypeError, ValueError):
 pass

 # conversion to the original parent failed
 # we try if it works with the corresponding complex domain
 if org_parent is float:
 try:
 return complex(res)
 except (TypeError, ValueError):
 pass
 elif hasattr(org_parent, 'complex_field'):
 try:
 return org_parent.complex_field()(res)
 except (TypeError, ValueError):
 pass

 return res
cdef class BuiltinFunction(Function):
@@ 831,6 +775,64 @@
# we should never end up here
raise ValueError, "cannot read pickle"
+ def __call__(self, *args, coerce=True, hold=False,
+ dont_call_method_on_arg=False):
+ """
+ Evaluate this function on the given arguments and return the result.
+
+ EXAMPLES::
+
+ sage: exp(5)
+ e^5
+ sage: gamma(15)
+ 87178291200
+ """
+ # we want to convert the result to the original parent if the input
+ # is not exact, so we store the parent here
+ org_parent = parent_c(args[0])
+
+ # if there is only one argument, and the argument has an attribute
+ # with the same name as this function, try to call it to get the result
+ # The argument dont_call_method_on_arg is used to prevent infinite loops
+ # when .exp(), .log(), etc. methods call this symbolic function on
+ # themselves
+ if len(args) == 1 and not hold and not dont_call_method_on_arg:
+ try:
+ return getattr(args[0], self._name)()
+ except AttributeError:
+ pass
+
+ res = super(BuiltinFunction, self).__call__(*args, coerce=coerce,
+ hold=hold)
+
+ # convert the result back to the original parent previously stored
+ # otherwise we end up with
+ # sage: arctan(RR(1))
+ # 1/4*pi
+ # which is surprising, to say the least...
+ if org_parent is not SR and \
+ (org_parent is float or org_parent is complex or \
+ (PY_TYPE_CHECK(org_parent, Parent) and \
+ not org_parent.is_exact())):
+ try:
+ return org_parent(res)
+ except (TypeError, ValueError):
+ pass
+
+ # conversion to the original parent failed
+ # we try if it works with the corresponding complex domain
+ if org_parent is float:
+ try:
+ return complex(res)
+ except (TypeError, ValueError):
+ pass
+ elif hasattr(org_parent, 'complex_field'):
+ try:
+ return org_parent.complex_field()(res)
+ except (TypeError, ValueError):
+ pass
+
+ return res
cdef class SymbolicFunction(Function):
"""