in order to port fast Add and Mul to SymPy, is the basic functionality
hidden in the TermCoeffDict class? If so, it should be pretty easy to
port it, right (nice job!)?
The Add in sympycore has some other funcitonality, some of which is in
SymPy, some other things aren't. But I am just concerned with the
speed, and it seems to me the TermCoeffDict is enough.
Another question - how does the ordering of classes work? I didn't
find it in the docs, nor I am completely sure I understand the sources
- if you could give me a few hints, it'd be awesome.
Ondrej
TermCoeffDict, BaseExpDict do most of the job.
> Another question - how does the ordering of classes work? I didn't
> find it in the docs, nor I am completely sure I understand the sources
> - if you could give me a few hints, it'd be awesome.
Ordering of classes is no longer needed: dicts store their keys in an
unordered fashion. Ordering is only required for printing expressions
in a consistent way.
Fredrik
I see. Like polynomials. The most important slowdown is imho spent in
things like
evaluating Add(x, x) and similar. So this should be all implemented in
TermCoeffDict.
> > Another question - how does the ordering of classes work? I didn't
> > find it in the docs, nor I am completely sure I understand the sources
> > - if you could give me a few hints, it'd be awesome.
>
> It is not in docs as it is implementation detail.
> First, one should realize that comparison is only
> needed in producing a nice output and the
> order is insignificant in commutative operations,
> hence, internally data will not be ordered which can
> be expensive. So, data is sorted in, say tostr, methods.
So printing is probably quite slow, isn't it?
> For equality checks of composite objects that represent
> commutative operations, the data is transformed
> to frozenset instances which will be checked for
> equality.
So let's say I want to do:
e = x+x
so TermCoeffDict.__new__(TermCoeffDict, x, x) get's called, which does
obj = dict.__new__(dict)
obj += x
obj += x
and dict.__iadd__() does the simplification to 2*x, is that correct?
That's pretty clever to subclass dict to provide a specialized very
fast dict for our purposes and then just call it from Add. Similarly
for Mul.
What is the difference between __iadd__ and inplaceadd()?
And canonical is for converting it to Add/Mul/Pow? I am not seeing if I write
e = x + y
where exactly it gets converted to the Add instance. In Add.__new__(),
the TermCoeffDict gets created, then as_Basic gets called, which
basically just returns canonical(), which returns just self (i.e.
TermCoeffDict), so I am not sure how it works exactly.
Ondrej
Not really.
t = x**2 + 3*y*(x+2*(1+x**2)) + 4*x + 5*y*x + y**3
s = str(t)
sympycore time:
0.0019
0.0010
sympyhg time:
0.0093
0.0018
I'd say printing is fast enough that we could afford to slow it down further,
for example, properly sorting terms by polynomial degree.
Fredrik
Is the first number for the "t=" line and the second number for the "s=" line?
Ondrej
Yes. Hit me if I made an error.
Fredrik
Yes, that's what I mean.
>
> > > > Another question - how does the ordering of classes work? I didn't
> > > > find it in the docs, nor I am completely sure I understand the sources
> > > > - if you could give me a few hints, it'd be awesome.
> >
> > > It is not in docs as it is implementation detail.
> > > First, one should realize that comparison is only
> > > needed in producing a nice output and the
> > > order is insignificant in commutative operations,
> > > hence, internally data will not be ordered which can
> > > be expensive. So, data is sorted in, say tostr, methods.
> >
> > So printing is probably quite slow, isn't it?
>
> Why should it be slower?
It isn't as Fredrik pointed out. But I am rather asking why is it faster? :)
I mean if you just print, or you first sort and then print, it seems
to me the second option should be slower.
> inplaceadd takes additional coefficent argument, __iadd__ is
> just an optimized version of inplaceadd.
I see, so iadd could be made using inplaceadd, but it was done faster? Ok.
> > And canonical is for converting it to Add/Mul/Pow? I am not seeing if I write
> >
> > e = x + y
> >
> > where exactly it gets converted to the Add instance. In Add.__new__(),
> > the TermCoeffDict gets created, then as_Basic gets called, which
> > basically just returns canonical(), which returns just self (i.e.
> > TermCoeffDict), so I am not sure how it works exactly.
>
> Look at the TermCoeffDict.as_Basic method. The result
> of canonical can either be TermCoeffDict or Basic
> instance. If the former then the Add instance will be
> created and the TermCoeffDict instance will be set
> as _dict_content attribute.
I am stupid, I've looked into that, but I misinterpreted the code.
Yep, so the TermCoeffDict seems to be pretty selfcontained and easy to
port. Let's see how it goes.
Thanks for the explanations,
Ondrej
If you find things that are not obvious, and figure them out, please add
comments to the code (and offer them back to sympycore).
Fredrik