Hi, On Sun, Jul 19, 2009 at 3:11 PM, William Stein<wst...@gmail.com> wrote: >>> Or should we just restore old "diff" by simply sub-classing it >>> from SFunction like what is being done for "integration" >>> and others? > > At first glance doing this sounds like a really good idea. How hard > would it be for you to make a mock-up prototype of this to more > clearly demonstrate it? I'm definitely not opposed.
OK, here is a prototype implementation. This is based on the principle that we stop applying chain rule when we hit a symbolic function and whose derivative isn't defined in sage/pynac. These are the output from my sage console --------- sage: f(x) = function('f',x) sage: f(x).diff(x) diff(f(x), x, 1) sage: f(x).diff(x,2) diff(f(x), x, 2) sage: sin(cos(f(x))).diff(x) -sin(f(x))*cos(cos(f(x)))*diff(f(x), x, 1) sage: f(sin(x)).diff(x) diff(f(sin(x)), x, 1) --------- I have done three things: (1) Defined a symbolic derivative wrapper SFunction (attached). Frankly, this is not much different than: diff = function('diff') (2) Added a small wrapper cython function in symbolic/pynac.pyx as cdef public object py_derivative(unsigned id, object var, object args) except +: """ """ cdef SFunction func = get_sfunction_from_serial(id) assert(func is not None) from sage.symbolic.derivative import newdiff return newdiff(func(*args), var) (3) Added a condition in "function.cpp" in pynac such that it calls "py_derivative" instead of applying chain rule when it hits a symbolic function and whose derivative function is not defined. // No derivative defined? Then dont apply chain rule if (opt.derivative_f == NULL) { // convert seq to a PyTuple of Expressions PyObject* args = exvector_to_PyTuple(seq); PyObject* dvar = ex_to_pyExpression(s); PyObject* pyresult = py_derivative(serial, dvar, args); Py_DECREF(args); Py_DECREF(dvar); if (!pyresult) { throw(std::runtime_error("function::derivative(): python function raised exception")); } // convert output Expression to an ex ex result = pyExpression_to_ex(pyresult); Py_DECREF(pyresult); if (PyErr_Occurred()) { throw(std::runtime_error("function::derivative(): python function (pyExpression_to_ex) raised exception")); } return result; Notes: This is not the fastest implementation but my current priority is to get my work done even if it takes bit longer rather than not able to do at all. Cheers, Golam --~--~---------~--~----~------------~-------~--~----~ To post to this group, send email to sage-devel@googlegroups.com To unsubscribe from this group, send email to sage-devel-unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/sage-devel URLs: http://www.sagemath.org -~----------~----~----~----~------~----~------~--~---
""" Symbolic Derivative """ from sage.symbolic.function import SFunction, sfunctions_funcs class SymbolicDerivative(SFunction): def __init__(self, *args, **kwds): """ EXAMPLES:: """ kwds['built_in_function'] = True for name in sfunctions_funcs: if hasattr(self, "_%s_"%name): kwds['%s_func'%name] = getattr(self, "_%s_"%name) SFunction.__init__(self, "diff", *args, **kwds) def _eval_(self, *args, **kwds): """ Returns the results of symbolic evaluation """ # Two arguments comes only from pynac call. Others are # self call. if len(args) != 2: return None f = args[0] x = args[1] if x not in f.args(): return 0 if f.operator() == newdiff: nargs = list(f.operands()) new_var = True n = len(nargs) for j in range(1,n,2): if x == nargs[j]: nargs[j+1] = nargs[j+1] + 1 new_var = False break if new_var: nargs.append(x) nargs.append(1) return self.__call__(*nargs) return self.__call__(f, x, 1) newdiff = SymbolicDerivative()