GSoC Week 12
Last week I told you why rs_series
doesn’t work with negative or fractional
powers because of the constraints of a polynomial back-end and why we need to
modify polys
. The situation isn’t that hopeless actually. Let’s talk about
negative and fractional powers one by one.
Negative Powers
The reason negative exponents work in ring_series
is because I modified
PolyElement
to allow so. In hind sight, it wasn’t the right decision and needs
to be replaced with something that doesn’t alter polys
. It is rather
surprising that I came across a possible solution so late (Now we know why good
documentation is so important).
I already knew that polys
allows us to create a FractionField
. A fraction
field over a domain R
consists of elements of the form a/b
where a
and b
belong to R
. In our case we are interested in the fraction field of polynomial
ring, i.e, fractions with polynomials as numerator and denominator. So a/b
is
not a * b**(-1)
but is a / b
, where a and b are polynomials.
What was new to me was that just like ring
, polys
also has sparse field
.
In effect, it allows us to create sparse rational functions without altering
anything.
I modified some functions in ring_series
to work with a rational function
field here, and it works quite well indeed.
In [42]: from sympy.polys.fields import *
In [43]: F, a, b = field('a, b', QQ)
In [44]: p = rs_sin(a + b, a, 3)/a**5
In [45]: p*a
Out[45]: (-3*a**2*b - 3*a*b**2 + 6*a - b**3 + 6*b)/(6*a**4)
Note that all these are field operations and I haven’t modified field.py
in
any way. Elegant!
But then again, having a field increases the complexity as we need to evaluate the numerator and denominator separately.
Fractional Powers
Fractional powers are a much trickier case as there is no simple solution to it as
above. What we can do is optimise the option I had presented in my last post,
i.e, have each fractional power as a generator. But doing that opens up a
Pandora’s box. Simple things such as sqrt(a)**2 == a
do not hold true any
more. The current rs_series
treats sqrt(a)
as a constant if we are expanding
with respect to a
:
In [22]: rs_series(sin(a**QQ(1,2)), a**QQ(1,2),5)
Out[22]: -1/6*(sqrt(a))**3 + (sqrt(a))
In [23]: rs_series(sin(a**QQ(1,2)), a,5)
Out[23]: sin(sqrt(a))
So, if we indeed decide to tread this path, we would need to replace a
here
with sqrt(a)**2
. This really complicates the situation as we need to figure
out what to replace with. In any calculation the powers change multiple times
and each time we’ll need to figure out how to rewrite the series.
Next Week
It is now mostly a design decision whether we want the ring_series
to be
confined within the polys
module. The polys
environment allows efficient
manipulations of laurent series (with FracField
), but I doubt we can achieve
the speed we want with puiseux series without modifying polys
. One possible
solution is to separate the modified parts of polys
along with ring_series
from polys
. We are using polys
only because it has the data structure that
we want. Separating them would allow us to simultaneously make use of its
back-end and not introduce unnecessary complexity in our representation.
Other than that, documentation is another priority now. I had planned to do it earlier too, but couldn’t. This week’s discovery has reminded me of its importance.
Cheers!
Enjoy Reading This Article?
Here are some more articles you might like to read next: