On Thu, 14 Apr 2022 at 23:22, Aaron Meurer <[email protected]> wrote: > > On Thu, Apr 14, 2022 at 3:12 PM Oscar Benjamin > <[email protected]> wrote: > > > > On Thu, 14 Apr 2022 at 20:30, Aaron Meurer <[email protected]> wrote: > > > > > > On Thu, Apr 14, 2022 at 12:26 PM Oscar Benjamin > > > <[email protected]> wrote: > > > > > > > > As an example it would be trivial in SymPy to make substitutions > > > > involving large expressions and many replacements much faster with a > > > > small redesign. The problem though is backwards compatibility: each > > > > expression class can implement its own _eval_subs method so for > > > > backwards compatibility the subs implementation must recurse in the > > > > same slow way once throughout the whole tree for each replacement that > > > > is to be made. (There are ways to work around this but the design > > > > makes it harder than it should be.) > > > > > > Just to be clear, isn't this already fixed with xreplace, which does > > > only replacement with no smart substitution and no dispatching to > > > _eval methods? That isn't to say xreplace itself couldn't be more > > > performant, which I'm sure it could. > > > > Even xreplace runs the evaluation code which is baked into __new__. > > Right, so the "redesign" isn't so much about the substitution but > rather in removing automatic evaluation.
Removing automatic evaluation can mean different things. Automatic evaluation is nice from a user perspective for most tasks (but not all). Automatic evaluation is a nightmare from an algorithmic perspective if you don't have any good way to control it. Right now it isn't possible to distinguish between an internal operation for which evaluation should be postponed and a user-facing operation for which it might be desired: everything goes through the same __new__ so even xreplace can't get around it. The class-based design makes it possible to design classes that are completely broken if you don't let them evaluate and also means that the choice to evaluate lies with each class. In any case what I'm talking about is still not just about evaluation. It's about representing expressions with data structures rather than polymorphic classes. It should be possible to define something like a tan function and then use different kinds of data structures to represent expressions involving that function. The design should not be tied to any particular data structure and that means that tan can not be a class that chooses its own internal representation for any expression involving the tan function. Of course the lower-level data structures wouldn't have automatic evaluation though (you wouldn't expect a dict or a list to "evaluate"). > > Also it recurses down through all of the args in the tree which can in > > many cases be done much more efficiently if the expression is > > represented as a DAG rather than a tree. > > Not sure that's so hard to do with the current design. I think it > would be possible to add some optimizations to effectively > de-duplicate identical subexpressions. I want a design where these things mostly just happen automatically. The current design seems to maximise the amount of procedural code that needs to be written which simultaneously maximises bugs and also the amount of work that is needed to optimise anything. > It's already basically possible > to do this, you just have to assume that == is not a slow operation > (which it mostly isn't, although it could be faster). It's slower than it should be. A different design can easily make it faster but not if you have classes that are allowed to define their own __eq__ methods. -- Oscar -- You received this message because you are subscribed to the Google Groups "sympy" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/CAHVvXxTz1YW0JQ7_ySkHNUsQQws1oVYxwZtLqhYznWzEQ0sgag%40mail.gmail.com.
