On Friday, August 17, 2012 5:18:49 PM UTC+3, smichr wrote:
>
> There is an rcollect function that you might look at.
>
Thanks, I had missed this. However, I tried it now and unless I'm doing
something wrong, it's not being recursive in the way I meant:
import sympy as sy
s = sy.sympify("a*b*c*d + b*c*d + c*d + d")
sy.rcollect(s, "d", "c", "b", "a")
gives
d*(a*b*c + b*c + c + 1)
whereas I'd like to get, and my code (symutil.recursive_collect("a*b*c*d +
b*c*d + c*d + d")) produces
d*(1 + c*(1 + b*(1 + a)))
(There was a mistake in my original message where I said "a * b * c * (1 +
d) ", which obviously is not equivalent with the original. That was quickly
written by hand out of laziness, and well, I got it wrong. The new, correct
expression is from actual program output.)
Looking at the source confirms that these two ideas of recursive collection
are different:
- SymPy's current rcollect() works by processing anything that matches
is_Add inside the expression tree. Hence, it is recursive in the sense that
a sum operation at any level in the expression tree will be collected
locally. Algorithmically, rcollect() uses a depth-first approach.
- My code works by collecting at the top level *first*, and only then
recurses into the args of the collected expr (doing the same top-level
collection for them, and recursing, etc.). Atoms are passed through as-is.
At each level, the current operation is finally rewritten using the
processed args. This extracts the nested multiplications in the example
above, because a successful collect() will produce a Mul. Algorithmically,
recursive_collect() uses a breadth-first approach.
A further difference is that recursive_collect() comes with an (optional)
automatic symbol list generation mechanism. If no "syms" are given by the
user, the "syms" list is automatically generated at each level in a way
such that the operation count of the subexpression is likely to be
minimized when it is collected.
E.g. when given the expanded expression (please excuse the symbol naming;
parts of this were automatically generated)
-A*phi_x*u_x - G*phi_y*u_y - __Ux__1__*__Ux__1___x*phi*rho*u_x -
__Ux__1__*__Uy__1___x*phi*rho*u_y - __Ux__1___y*__Uy__1__*phi*rho*u_x -
__Uy__1__*__Uy__1___y*phi*rho*u_y - 2*__Ux__1__*__Uy__1__*phi*rho*u_xy -
phi*rho*u_xx*__Ux__1__**2 - phi*rho*u_yy*__Uy__1__**2
my code using the automatic symbol list produces
phi*rho*(__Ux__1__*(-__Ux__1___x*u_x - __Uy__1___x*u_y - 2*__Uy__1__*u_xy)
+ __Uy__1__*(-__Ux__1___y*u_x - __Uy__1___y*u_y) - u_xx*__Ux__1__**2 -
u_yy*__Uy__1__**2) - A*phi_x*u_x - G*phi_y*u_y
which is (by an eyeball metric) at least near optimal regarding operation
count (at least when collecting is the only allowed simplification).
In conclusion, rcollect() and my suggested code do different things, so I
would still like to request consideration for whether the new functionality
would be useful in standard SymPy.
Why I personally think this would be a useful feature, is that the user may
only want to collect an expression to produce a reduction in operation
count, without being interested in which symbols should make up syms/vars
and in which order. Also, a global "optimal" list of syms/vars for this
purpose may not even exist: different subexpressions may be more
advantageous to collect using a different ordering of the symbols. The
automatic syms generation takes care of this. It is not intended to replace
manually provided syms/vars, but to complement it.
And finally, about rcollect():
- Is there a reason why the call syntax differs from collect()? collect()
takes in a list of syms, while rcollect() uses Python's *args mechanism for
the same (and calls them "vars", instead of "syms" like collect()).
- Suggestion for documentation: rcollect() could be mentioned in the
documentation for collect() to make it easier to find. At least I find it a
bit confusing that many of the other simplifiers come with a "deep" flag,
but for collect() the recursive version is a separate function. (Of course,
technically there is the distinction of descending into function arguments
vs. recursing into sums, so the difference may be justified.)
--
You received this message because you are subscribed to the Google Groups
"sympy" group.
To view this discussion on the web visit
https://groups.google.com/d/msg/sympy/-/GsXjNHijbrsJ.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/sympy?hl=en.