Week 4 and the final week of the first phase of the Coding Period is coming to an end. The work, which was initially proposed to be done in FormalPowerSeries
has been done on a term-by-term level, i.e. the operations which have been implemented return truncated terms of the resultant FormalPowerSeries
, instead of returning a FormalPowerSeries
object. Sartaj and I have already discussed about the class
implementation, in a recent meeting. Here are the deliverables which has been completed this week :–
- The PR #17017 consisted of a
convolve
function, which takes in a ordern
term, and returns the truncated terms of the resultant convoluted formal power series. TheAPI
of theconvolve
function was in line with theconvolution
function insympy.discrete.convolutions
. More specifically, it was –def convolve(self, other, x=None, n=6, cycle=0, dyadic=False, subset=False): """The logic of the code"""
Sartaj suggested that there should be a method kwarg, which can take in which
method
of convolution the user wants to apply, instead of passing various kwargs representing the various methods. So I changed theAPI
of the function, in lines with the above comment. Currently it is –def convolve(self, other, x=None, n=6, cycle=0, method=None): """The logic of the code"""
in which method will be one of
[dyadic, subset, None]
, and cycle will represent the no. of cycles in cyclic convolution. Docs have also been updated. The PR is now in a mergeable state !! - I also opened a [PR #17064], which deals with the
composition
andinversion
of formal power series. I had implemented aCoeffBell
class, where essentiallyCoeffBellCompose(f, n, k) represents Bell polynomials of the second kind
. Note that bothn
andk
should be integers. The implementation of theeval
function of theCoeffBell
class is as follows –@classmethod def eval(cls, f, n, k): fp = fps(f) kv = fp.ak.variables[0] i = symbols('i') if n.is_integer and k.is_integer: fp_seq = sequence(fp.ak.formula, (kv, 1, n-k+1)) fact_seq = sequence(factorial(i), (i, 1, n-k+1)) bell_seq = fp_seq * fact_seq return bell(n, k, tuple(bell_seq))
Then we can easily define bell sequences in terms of
CoeffBell
classes. Once we define them, all other terms can defined as sequences, and then the sequences can be multiplied and then the terms can be added up. Once we implement them, we can add up the sequence terms, and get the desired resultant truncated terms.
The various tests implemented here will give you an idea. They are :-
def test_fps__composition():
f1, f2, f3 = fps(exp(x)), fps(sin(x)), fps(cos(x))
raises(ValueError, lambda: f1.compose(sin(x), x))
raises(ValueError, lambda: f1.compose(fps(sin(x), dir=-1), x, 4))
raises(ValueError, lambda: f1.compose(fps(sin(x), x0=1), x, 4))
raises(ValueError, lambda: f1.compose(fps(sin(y)), x, 4))
raises(ValueError, lambda: f1.compose(f3, x))
raises(ValueError, lambda: f2.compose(f3, x))
assert f1.compose(f2, x) == 1 + x + x**2/2 - x**4/8 - x**5/15 + O(x**6)
assert f1.compose(f2, x, n=4) == 1 + x + x**2/2 + O(x**4)
assert f1.compose(f2, x, n=8) == \
1 + x + x**2/2 - x**4/8 - x**5/15 - x**6/240 + x**7/90 + O(x**8)
assert f2.compose(f2, x, n=4) == x - x**3/6 + O(x**4)
assert f2.compose(f2, x, n=8) == x - x**3/6 + 11*x**5/120 - 127*x**7/5040 + O(x**8)
def test_fps__inverse():
f1, f2, f3 = fps(sin(x)), fps(exp(x)), fps(cos(x))
raises(ValueError, lambda: f1.inverse(x))
raises(ValueError, lambda: f1.inverse(x, n=8))
assert f2.inverse(x) == 1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + O(x**6)
assert f2.inverse(x, n=8) == \
1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + x**6/720 - x**7/5040 + O(x**8)
assert f3.inverse(x) == 1 + x**2/2 + 5*x**4/24 + O(x**6)
assert f3.inverse(x, n=8) == 1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + O(x**8)
- Now that these implementations are over with, I have to start thinking about how we can make FormalPowerSeries objects as a result of these functions, instead of returning only the truncated terms. The first step in doing that would be to make all the sequences infinite, and save whatever sequence can be saved. Then we can create a sub-class out of
FormalPowerSeries
, which can have a custom_eval_terms
function which, instead of calculating term by term, will calculate the addition of all terms together. Once we have the basesub-class
ready, we can then move forward with creating three sub-classes out of the sub-class, one each forconvolve
,compose
, andinverse
. I will publish a PR, consisting of these changes, by the end of this week.
The first phase is over !! Phew !! See you in the next week. Adios till then !!