On Sat, 16 Apr 2022 at 02:53, Isuru Fernando <[email protected]> wrote:
>
> Hi Oscar,
>
> Here's a few things that are different in SymEngine than SymPy.
>
> > 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.)
>
> In SymEngine, classes do not have such a method and therefore cannot
> extend for eg: subs function.
> However the subs function itself (SubsVisitor class technically) can be
> extended.

Yes, this does work differently in SymEngine compared to SymPy. If
SymPy could be changed to work the same way then it could also be a
lot faster (without needing to be rewritten in C++). SymEngine has the
same overall design as SymPy but makes different choices for some
aspects of that design so that it is faster but at the same time
incompatible.

Can the SubsVisitor class be extended from Python?

> > This is a small example of a more general problem. Using classes means
> you have to use the interfaces of the class which means that efficient
> algorithms needing something not provided by that public interface are
> impossible. Even worse both SymPy and SymEngine allow the
> *constructors* of those classes to do nontrivial work without
> providing any good way to override that. This means that you can't
> even represent a symbolic expression without allowing arbitrary code
> execution: it's impossible to optimize higher-level algorithms if you
> have so little control over execution from the outside.
>
> No, SymEngine does not do anything in the constructor of the C++ class
> itself. (For eg: class "Add"). We have different functions (For eg: function 
> "add")
> that do complicated functionality to create the C++ class. A user is allowed
> to create the C++ class directly and we assume that the data structure that 
> the
> user passed is internally consistent in Release mode and we check user
> input in Debug mode. This allows the user to do low level optimizations
> when they know that going through the complicated function is unnecessary.

Does this only apply when working in C++? I just tried:

In [120]: from symengine import add, Add, symbols

In [121]: x = symbols('x')

In [122]: Add(x, x, evaluate=False)
Out[122]: 2*x

In [123]: add(x, x, evaluate=False)
Out[123]: 2*x

> > There are ways that this can be improved in both SymPy and SymEngine
> but I also think that for many important operations the basic design
> used by these is limiting in a big-O sense: the design constrains what
> algorithms can be used. SymEngine is faster than SymPy in a brute
> force sense by using C++ rather than Python but it would be possible
> to make something both faster and more flexible if a different design
> was used at a basic level.
>
> I disagree about this in SymEngine. For eg: SymPy's extensibility
> of classes prevents optimizations that SymEngine can do because symengine
> doesn't have an equivalence of `_eval_subs` or similar.
> Some of the optimizations in SymEngine like Aaron said leads to better
> big-O complexities. i.e. the ratio between the two modules is not always a
> constant as input size increases.

That's true and it is also true that in many cases SymPy's big-O can
be improved without radically changing the design. I think though that
it's possible to get a better trade-off of performance and flexibility
using very different approaches. I will make a demonstration of this
at some point.

Going forwards though for better integration of SymPy and SymEngine
what can be done? SymEngine is faster than SymPy for many important
operations because it does things differently. Most of those
differences are incompatible though so it can't be used as a dropin
replacement. Changing SymEngine to make it more compatible would be a
huge amount of work and would also make it a lot slower.

There are different things that integration could mean. One
possibility is just that SymPy could quietly make use of SymEngine
internally in e.g. trigsimp or something without the user really
noticing the difference (except maybe for speed). Another possibility
is that it could be made easier for a user to use SymEngine
expressions in combination with public API in SymPy so that some
functions would accept and return SymEngine expressions where
possible.

--
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/CAHVvXxSxa52x7hrGq9O4r0Jiwvfm_%2B5qw0XZCLo8GJPOaviMVQ%40mail.gmail.com.

Reply via email to