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()

Reply via email to