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.

Reply via email to