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 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.