On May 25, 2012, at 3:41 PM, "krastanov.ste...@gmail.com" <krastanov.ste...@gmail.com> wrote:
>>> An example from the (upcoming) differential geometry module: >>> >>> p is a point with x=a and y=b >>> >>> rect is the Cartesian coordinate system >>> rect.x (y) are ScalarFields taking a point and returning the x (y) >>> coordinate >>> polar is the polar coordinate system with r and theta as basis fields >>> >>> rect.d_dx is the unit vector along x >>> rect.d_dy, polar.d_dr, polar.d_dtheta are the other unit vectors >>> >>> now the examples >>> >>> Creating scalar fields without the need for special scalar field >>> subclass of Expr: >>> >>> rect.x(p) = a >>> (rect.x+rect.y**2) = a+b**2 >>> >>> Creating vector fields (i.e. directional derivatives) without the need >>> for subclasses of Expr: >>> >>> (polar.d_dr+polar.d_theta) ( rect.x + 3 ) (p) = cos(theta(p)) + >>> r(p)*sin(theta(p)) >>> # I was to lazy to calculate r(p) and theta(p) >>> >>> This can be done with a helper function (e.g. `apply(field, point)`) >>> but the current approach seems nicer. >> >> If you do that, you won't have any simple way of recognising >> ScalarFields, or things-like-rect.d_dx (what do you call them?), which >> seems rather inconvenient. Worse than that, objects like (rect.x * >> rect.d_dx) cannot possibly work satisfactorily. > > Why would I want to recognize them? It is all about interface, not > what class they are. > > The other example ( x * d_dx ) is nonsensical mathematically. If a > user has a formalism in which it makes sense, he is free to use it, > that is all. > > Off topic: d_dx is the unit vector along x. It needs better name. (in > latex it is \frac{\part}{\part x}) > >>> >>> >>> Moreover, I still do not think that there are any special cases, as >>> there were no test failures when the change was done. >> >> The absence of test failures only shows that a feature that didn't exist >> wasn't used. As for special cases, I already mentioned the Expr vs Basic >> thing (why is this implemented only for Expr, when callability is >> unrelated to the concept of Expr?), but the special handling of Symbol >> is also a problem and the complicated implementation of Expr.__call__ >> probably makes assumptions that can be broken. Also, if any Expr >> subclass with a Lambda in its args will cause problems. I agree that could be an issue. Perhaps this could be an argument for not putting it in Basic, that a Basic (but not Expr) object is more likely to have some Lambda somewhere in its args that doesn't expect to be recursively called. Do we have any classes in SymPy with Lambda in their .args? >> > Yes, I agree. These should be discussed further, however I do not > think that these are show-stoppers. I would prefer to finish with the > examples from Aaron before proceeding on this. Most of my examples are syntactic sugar (but I guess this whole thing is just syntactic sugar). A nice example would be replace. You could do expr.replace(sin**2 + cos**2, 1). Right now you'd either have to do expr.replace(Lambda(x, sin(x)**2 + cos(x)**2), 1) or expr.replace(sin(a)**2 + cos(a)**2, 1), where a = Wild('a'). But actually it would be more useful than even just that. Anywhere where you would use Lambda or .subs(x, y) (or defining a simple Python function that returns an expression), you could just use this instead. So instead of something like def my_expr(x): return some_SymPy_expression_in_terms_of_x you could just have the expression itself, as a function. This is somewhat related to my previous discussion about replacing f(x, y) with an expression evaluated at x and y (see https://groups.google.com/forum/?hl=en_US&fromgroups#!searchin/sympy/evaluate/sympy/TsRxB8HnUuI/moOq251RBpcJ). If this were implemented I could just do expr.subs(psi, z**Id[1]*exp(-I*omega(z)*Id[2]) (this is also why we need a more powerful identity function, as I noted on the issue). I know that Lambdas can be used to do a lot of these things, but Lambda is inherently crippled in that if you want to mainpulate the expression in the Lambda at all, you have to peel off the Lambda first. With this, you don't have to do any of that. You can even use Lambdas if you want, though if you do, you can run into the issue where some part of an expression is "stuck" in the Lambda (like Lambda(x, x + 1) - 1). As another example, if I have an iterative function, like f(xn) = x_(n - 1)*(x_(n - 1) - 1) You can compute something like, f = Lambda(x, x*(x - 1)) # or Id*(Id - 1) f2 = f(f) f3 = f2(f) and then f, f2, and f3 are all callables, for which you can just say f(0.3), f2(0.3), f3(0.3) and get numbers back. In short, you eliminate the need for named dummy variables with this, because they aren't there at all. I can attest from my personal experience that this sort of thing would be very useful. I use these patterns quite often, especially the .subs(x, y) pattern, and I've often felt that if I could define the whole expression as a function directly that it would make things much easier. I've done the def my_expr(x): ... thing, and (when I remember that it exists) created a Lambda, but those are both limited in that the expression is "stuck" inside the function or Lambda (at least with Lambda you can see what it is and get it out if you want, though). If I want to perform any kind of simplification or modify the expression at all I have to recreate the function or Lambda. Aaron Meurer -- You received this message because you are subscribed to the Google Groups "sympy" group. To post to this group, send email to sympy@googlegroups.com. To unsubscribe from this group, send email to sympy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sympy?hl=en.