Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GSoC] Implemented convolution operation of two formal power series #17017

Merged
merged 7 commits into from Jul 4, 2019
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
84 changes: 83 additions & 1 deletion sympy/series/formal.py
Expand Up @@ -16,14 +16,15 @@
from sympy.core.singleton import S
from sympy.core.symbol import Wild, Dummy, symbols, Symbol
from sympy.core.sympify import sympify
from sympy.discrete.convolutions import convolution
from sympy.functions.combinatorial.factorials import binomial, factorial, rf
from sympy.functions.elementary.integers import floor, frac, ceiling
from sympy.functions.elementary.miscellaneous import Min, Max
from sympy.functions.elementary.piecewise import Piecewise
from sympy.series.limits import Limit
from sympy.series.order import Order
from sympy.simplify.powsimp import powsimp
from sympy.series.sequences import sequence
from sympy.series.sequences import sequence, SeqMul
from sympy.series.series_class import SeriesBase


Expand Down Expand Up @@ -1143,6 +1144,87 @@ def integrate(self, x=None, **kwargs):

return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind))

def convolve(self, other, x=None, n=6, cycle=0, dyadic=False, subset=False):
leosartaj marked this conversation as resolved.
Show resolved Hide resolved
""" Convolute two Formal Power Series and return the truncated terms upto specified order.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this return the product of two power series? If so, then I think that the method should be renamed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes currently it does that. But if we implement other types of convolution like dyadic or cyclic convolution, then they are no longer product of two power series. So I think, we should keep it convolute. I will try to extend the code to integrate cyclic, dyadic and other types of convolution into it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ArighnaIITG ,

How do you plan to add new types of convolution in the future?

If they will be separate methods, I believe renaming it to product is good like @jksuom suggested.

or one way will be to allow a method kwarg, eg. f1.convolve(f2, method='linear').


Parameters
==========

n : Number, optional
Specifies the order of the term upto which the polynomial should
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Specifies the order of the term upto which the polynomial should
Specifies the order of the term up to which the polynomial should

be truncated.
cycle : Integer
Specifies the length for doing cyclic convolution.
dyadic : bool
Identifies the convolution type as dyadic (*bitwise-XOR*)
convolution, which is performed using **FWHT**.
subset : bool
Identifies the convolution type as subset convolution.

Examples
========

>>> from sympy import fps, sin, exp, convolution
>>> from sympy.abc import x
>>> f1 = fps(sin(x))
>>> f2 = fps(exp(x))

>>> f1.convolve(f2, x, 4)
x + x**2 + x**3/3 + O(x**4)

>>> f1.convolve(f2, x, 4, cycle=4)
11*x/12 + 35*x**2/36 + x**3/3 + O(x**4)

>>> f1.convolve(f2, x, 6, dyadic=True)
4667/4800 + 2641*x/2880 + x**3/3 + x**4/60 + x**5/20 + O(x**6)

>>> f1.convolve(f2, x, 6, subset=True)
x + x**3/3 + x**5/20 + O(x**6)

See Also
========

sympy.discrete.convolutions
"""
if x is None:
x = self.x
if n is None:
return iter(self)

other = sympify(other)

if not isinstance(other, FormalPowerSeries):
raise ValueError("Both series should be an instance of FormalPowerSeries"
" class.")

if self.dir != other.dir:
raise ValueError("Both series should be calculated from the"
" same direction.")
elif self.x0 != other.x0:
raise ValueError("Both series should be calculated about the"
" same point.")

elif self.x != other.x:
raise ValueError("Both series should have the same symbol.")

if cycle > n:
raise ValueError("Value of cycle should be less than or equal to n.")
leosartaj marked this conversation as resolved.
Show resolved Hide resolved

k = self.ak.variables[0]
coeff1 = sequence(self.ak.formula, (k, 0, n-1))

k = other.ak.variables[0]
coeff2 = sequence(other.ak.formula, (k, 0, n-1))

conv_coeff = convolution(coeff1, coeff2, cycle, None, None, dyadic, subset)
conv_seq = sequence(tuple(conv_coeff), (k, 0, n-1))

k = self.xk.variables[0]
xk_seq = sequence(self.xk.formula, (k, 0, n-1))
terms = xk_seq * conv_seq

return Add(*terms) + Order(self.xk.coeff(n), (self.x, self.x0))

def __add__(self, other):
other = sympify(other)

Expand Down
24 changes: 24 additions & 0 deletions sympy/series/tests/test_formal.py
Expand Up @@ -507,3 +507,27 @@ def test_fps__operations():
fi = f2.integrate(x)
assert fi.function == sin(x)
assert fi.truncate() == x - x**3/6 + x**5/120 + O(x**6)

def test_fps__convolution():
f1, f2, f3 = fps(sin(x)), fps(exp(x)), fps(cos(x))

raises(ValueError, lambda: f1.convolve(exp(x), x))
raises(ValueError, lambda: f1.convolve(fps(exp(x), dir=-1), x, 4))
raises(ValueError, lambda: f1.convolve(fps(exp(x), x0=1), x, 4))
raises(ValueError, lambda: f1.convolve(fps(exp(y)), x, 4))

assert f1.convolve(f2, x, 3) == x + x**2 + O(x**3)
assert f1.convolve(f2, x, 4) == x + x**2 + x**3/3 + O(x**4)
assert f1.convolve(f3, x, 4) == x - 2*x**3/3 + O(x**4)

assert f1.convolve(f2, x, 4, cycle=4) == 11*x/12 + 35*x**2/36 + x**3/3 + O(x**4)
assert f1.convolve(f3, x, 4, cycle=3) == -S(2)/3 + x + x**2/12 - 2*x**3/3 + O(x**4)
raises(ValueError, lambda: f1.convolve(f2, x, 4, cycle=6))

assert f1.convolve(f2, x, 6, dyadic=True) == \
S(4667)/4800 + 2641*x/2880 + x**3/3 + x**4/60 + x**5/20 + O(x**6)
assert f1.convolve(f3, x, 5, cycle=4, dyadic=True) == 9*x/8 - 97*x**3/144 + O(x**5)

assert f1.convolve(f2, x, 6, subset=True) == x + x**3/3 + x**5/20 + O(x**6)
assert f1.convolve(f3, x, 5, cycle=5, subset=True) == \
S(1)/24 + x - x**2/144 - 2*x**3/3 + O(x**5)