-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 I like the proposed plan.
I also agree with Nick on derivative() vs diff(), but since the plan says that both will be around, I can probably live with that. Best, Alex Nick Alexander wrote: | As the author of the one of the patches, possibly soon to be | obsolete, I like this proposal. | | The one thing I don't like is the name. I prefer nouns, as in | A.derivative(). A.diff() is short for A.differentiate(), which | sounds like an in place procedure to me. | | Standardizing on an abbreviation is madness! My preferred examples | are characteristic polynomials and coefficients of polynomials. If I | want a characteristic polynomial, I look for that, not 'charpoly'. | Also, in many places A.coefficients() or A.coefficient_list() is | abbreviated A.coeffs(). It makes it harder to search. | | If I know what I want (a derivative!) that's what I will look for. | Not a diff. | | Nick | | PS. IIRC, the patch in trac would optimize only the case derivative | (x, 3). | | On 24-Feb-08, at 6:37 AM, David Harvey wrote: | |> After hearing some ideas on IRC regarding the derivatives mess, in |> this email I propose a plan. It's rough around the edges. Comments |> welcome. |> |> |> CURRENT SITUATION |> |> There are currently at least 18 different functions for |> differentiation in Sage, attached to polynomials, power series, |> symbolics, and other things. (See my previous email for a complete |> list.) |> |> There are about 4 "diff", 12 "derivative", one "differentiate", and |> sometimes (but not always) these names are aliases to each other. |> |> I count six different call signatures (all "derivative"s replaced by |> "diff" in the following list): |> |> def diff(self): mainly for univariate polynomial and power series |> types. |> |> def diff(self, verbose=None): only in the sage.functions.elementary |> module. All doctests are switched off on this file. The documentation |> says that this function *integrates* things! The verbose flag seems |> to be something passed to maxima. |> |> def diff(self, *args): only in calculus.calculus.SymbolicExpression. |> This is the most powerful version, and is the closest to what I want |> to eventually support everywhere. |> |> def diff(f, *args, **kwds): only in calculus.functional. This is a |> global, and just dispatches to the diff method on f. |> |> def diff(self, variable, have_ring=False): in the libsingular |> multivariate polynomial code, and also mysteriously crops up in |> polynomial_modn_dense_ntl.pyx. The parameter "have_ring" seems to be |> ignored everywhere, and somewhere claims that it is needed for |> "compatibility reasons". But I can't figure out what this means. |> |> def diff(self, var='x', n=1): only in |> interfaces.maxima.MaximaElement. It means differentiate n times with |> respect to x. Note that the variable is supplied as a *string*. We |> might want to leave this one out of the discussion; I guess here the |> diff function is supposed to conform to maxima semantics (about which |> I know nothing) rather than fit into the sage object model. |> |> There are three open tickets on this issue: |> |> http://trac.sagemath.org/sage_trac/ticket/756 (patch is problematic) |> http://trac.sagemath.org/sage_trac/ticket/753 (not much interesting |> here) |> http://trac.sagemath.org/sage_trac/ticket/1578 (there's a patch here, |> might need to get superseded, sorry Nick) |> |> There are two separate issues here: function naming, and function |> signatures. The former is much simpler, so I'll discuss that first. |> |> |> FUNCTION NAMING |> |> I propose that we deprecate "differentiate". |> |> I propose that we use "diff" as the basic name, and have "derivative" |> as an alias for any object supporting "diff". |> |> I propose that there be a lower-level function "_diff" with a simpler |> signature, see below. |> |> |> FUNCTION SIGNATURES |> |> Here is an approximation to what I would like to see. |> |> Any object F supporting differentiation should have a function |> "_diff" (def or cpdef) taking at least one argument var=None. It can |> have additional arguments, but these must be optional. For example: |> def _diff(self, var=None) |> def _diff(self, var=None, have_ring=False) |> def _diff(self, var=None, verbose=False) |> |> If var is supplied, it should be a variable object (for example, a |> symbolic variable, or a generator of a polynomial ring). It need not |> lie in the parent of F. Examples: |> |> * If F is in S[x] for some ring S, and you call F._diff(x), you get |> what you expect. |> * If F is in S[x] for some ring S, and you call F._diff(y), then |> G._diff(y) gets called for each coefficient of F. |> * If F is in the symbolic ring, then var can be any symbolic variable. |> |> If var is None, the object makes a decision about the default |> variable and uses that. For example: |> |> * a univariate polynomial or power series will differentiate w.r.t. |> the generator. |> * a symbolic expression containing precisely one variable will use |> that variable. |> * a multivariate polynomial will raise an exception. |> * a symbolic expression containing more than one variable will raise |> an exception. |> |> Now we come to the "diff" method. It must have an "*args"-style |> argument, which must be interpreted according to the following list |> of examples (which is almost clear enough to serve as a |> specification :-)): |> |> F.diff(): equivalent to F._diff(None) |> F.diff(2): equivalent to F._diff(None)._diff(None) |> F.diff(x): equivalent to F._diff(x) |> F.diff(x, 3): equivalent to F._diff(x)._diff(x)._diff(x) |> F.diff(x, y): equivalent to F._diff(x)._diff(y) |> F.diff(x, 3, y, 2, z): equivalent to F._diff(x)._diff(x)._diff |> (x)._diff(y)._diff(y)._diff(z) |> F.diff(2, x): equivalent to F._diff(None)._diff(None)._diff(x) |> [this one currently causes an infinite loop for symbolic objects!] |> F.diff([x, y, z]): equivalent to F._diff(x)._diff(y)._diff(z) |> F.diff((x, y, z)): equivalent to F._diff(x)._diff(y)._diff(z) |> |> For the list and tuple versions, it must be the only parameter, and |> repetition counts are not allowed. |> |> When I say "equivalent" in the above descriptions, I don't mean it |> literally has to call _diff that way, I just mean the behaviour |> should be equivalent. |> |> Discussion on IRC concluded that partial derivatives need not |> commute, so we always have to do the derivatives in the order |> specified. (Of course implementations are free to use commutativity |> if they know about it, but the general case shouldn't assume it.) |> |> To avoid code duplication, there will be two global helper functions. |> |> The first one is |> def diff_parse(args) |> which takes a list/tuple like [2, x, 3, y] and converts it to a list/ |> tuple like [None, None, x, x, x, y]. |> |> The second one is |> def multi_diff(F, args): |> for arg in args: |> F = F._diff(arg) |> return F |> |> Therefore it will always be possible to implement diff via just: |> def diff(self, *args): |> return multi_diff(self, diff_parse(args)) |> as long as _diff has been implemented (which it should have been!) |> |> Of course you can put in a more efficient implementation if you want, |> for example for univariate polynomials it might be: |> def diff(self, *args): |> if not args: |> return self._diff() |> return multi_diff(self, diff_parse(args)) |> |> And of course a caller is always free to directly call _diff instead |> of diff, if they know exactly what they want. |> |> NOTE: conspicuously absent is the **kwds parameter in the above spec. |> I don't know quite how to do this in an efficient way. I'm worried |> the overhead will kill us in the last example. Any thoughts about |> this are welcome. |> |> david |> |> |> | | | | - -- Alexandru Ghitza Assistant Professor Department of Mathematics Colby College Waterville, ME 04901 http://bayes.colby.edu/~ghitza/ -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.7 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFHwciodZTaNFFPILgRAmaVAJ9vm+1F0wp7a6wLOJBy+J84qbmD6QCfYPxI NoCxrnZ9hsyeObmsgLlingE= =u4/l -----END PGP SIGNATURE----- --~--~---------~--~----~------------~-------~--~----~ To post to this group, send email to sage-devel@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/sage-devel URLs: http://www.sagemath.org -~----------~----~----~----~------~----~------~--~---