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

Implementing Sequences #9435

Merged
merged 19 commits into from Jun 14, 2015
Merged
Show file tree
Hide file tree
Changes from 18 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
53 changes: 49 additions & 4 deletions sympy/core/tests/test_args.py
Expand Up @@ -9,7 +9,7 @@
import warnings
import io

from sympy import Basic, S, symbols, sqrt, sin, oo, Interval, exp
from sympy import Basic, S, symbols, sqrt, sin, oo, Interval, exp, Lambda
from sympy.core.compatibility import range
from sympy.utilities.pytest import XFAIL, SKIP
from sympy.utilities.exceptions import SymPyDeprecationWarning
Expand Down Expand Up @@ -240,7 +240,6 @@ def test_sympy__core__function__Function():


def test_sympy__core__function__Lambda():
from sympy.core.function import Lambda
assert _test_args(Lambda((x, y), x + y + z))


Expand Down Expand Up @@ -498,7 +497,7 @@ def test_sympy__sets__fancysets__Reals():

def test_sympy__sets__fancysets__ImageSet():
from sympy.sets.fancysets import ImageSet
from sympy import S, Lambda, Symbol
from sympy import S, Symbol
Copy link
Member

Choose a reason for hiding this comment

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

Perhaps symbols are already imported above, you can use that.

Copy link
Member Author

Choose a reason for hiding this comment

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

I needed to importLambda, which was imported multiple times already. So, I took it out. Well, I will try to cleanup other imports as well. 👍

x = Symbol('x')
assert _test_args(ImageSet(Lambda(x, x**2), S.Naturals))

Expand Down Expand Up @@ -2065,7 +2064,7 @@ def test_sympy__matrices__expressions__determinant__Determinant():

def test_sympy__matrices__expressions__funcmatrix__FunctionMatrix():
from sympy.matrices.expressions.funcmatrix import FunctionMatrix
from sympy import Lambda, symbols
from sympy import symbols
Copy link
Member

Choose a reason for hiding this comment

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

same here.

i, j = symbols('i,j')
assert _test_args(FunctionMatrix(3, 3, Lambda((i, j), i - j) ))

Expand Down Expand Up @@ -3006,6 +3005,52 @@ def test_sympy__series__order__Order():
assert _test_args(Order(1, x, y))


@SKIP('Abstract Class')
def test_sympy__series__sequences__SeqBase():
pass


def test_sympy__series__sequences__EmptySequence():
from sympy.series.sequences import EmptySequence
assert _test_args(EmptySequence())


@SKIP('Abstract Class')
def test_sympy__series__sequences__SeqExpr():
pass


def test_sympy__series__sequences__SeqPer():
from sympy.series.sequences import SeqPer
assert _test_args(SeqPer((1, 2, 3), (0, 10)))


def test_sympy__series__sequences__SeqFormula():
from sympy.series.sequences import SeqFormula
assert _test_args(SeqFormula(x**2, (0, 10)))


def test_sympy__series__sequences__SeqExprOp():
from sympy.series.sequences import SeqExprOp, sequence
s1 = sequence((1, 2, 3))
s2 = sequence(x**2)
assert _test_args(SeqExprOp(s1, s2))


def test_sympy__series__sequences__SeqAdd():
from sympy.series.sequences import SeqAdd, sequence
s1 = sequence((1, 2, 3))
s2 = sequence(x**2)
assert _test_args(SeqAdd(s1, s2))


def test_sympy__series__sequences__SeqMul():
from sympy.series.sequences import SeqMul, sequence
s1 = sequence((1, 2, 3))
s2 = sequence(x**2)
assert _test_args(SeqMul(s1, s2))


def test_sympy__simplify__hyperexpand__Hyper_Function():
from sympy.simplify.hyperexpand import Hyper_Function
assert _test_args(Hyper_Function([2], [1]))
Expand Down
19 changes: 19 additions & 0 deletions sympy/printing/latex.py
Expand Up @@ -1497,6 +1497,25 @@ def _print_Range(self, s):
+ r", ".join(self._print(el) for el in printset)
+ r"\right\}")

def _print_SeqFormula(self, s):
if s.start is S.NegativeInfinity:
stop = s.stop
printset = ('\ldots', s.coeff(stop - 3), s.coeff(stop - 2),
s.coeff(stop - 1), s.coeff(stop))
elif s.stop is S.Infinity or s.length > 4:
printset = s[:4]
printset.append('\ldots')
else:
printset = tuple(s)

return (r"\left\["
+ r", ".join(self._print(el) for el in printset)
+ r"\right\]")

_print_SeqPer = _print_SeqFormula
_print_SeqAdd = _print_SeqFormula
_print_SeqMul = _print_SeqFormula

def _print_Interval(self, i):
if i.start == i.end:
return r"\left\{%s\right\}" % self._print(i.start)
Expand Down
23 changes: 22 additions & 1 deletion sympy/printing/pretty/pretty.py
Expand Up @@ -1496,7 +1496,6 @@ def _print_Complement(self, u):
parenthesize=lambda set: set.is_ProductSet or set.is_Intersection
or set.is_Union)


def _print_ImageSet(self, ts):
if self._use_unicode:
inn = u("\N{SMALL ELEMENT OF}")
Expand All @@ -1518,6 +1517,28 @@ def _print_Contains(self, e):
else:
return prettyForm(sstr(e))

def _print_SeqFormula(self, s):
Copy link
Member

Choose a reason for hiding this comment

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

_print_SeqBase could be used here instead - then you wouldn't need the additional methods for SeqAdd, etc... This goes for all the printers you've done.

Copy link
Member Author

Choose a reason for hiding this comment

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

That will cause issues

In [1]: from sympy.series.sequences import SeqExpr

In [2]: s = SeqExpr(n**2)

In [3]: s
Out[3]: ---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-3-f4d5d0c0671b> in <module>()
----> 1 s

/home/leosartaj/projects/sympy/my/lib/python2.7/site-packages/IPython/core/displayhook.pyc in __call__(self, result)
    251             self.write_output_prompt()
    252             format_dict, md_dict = self.compute_format_data(result)
--> 253             self.write_format_data(format_dict, md_dict)
    254             self.update_user_ns(result)
    255             self.log_output(format_dict)

/home/leosartaj/projects/sympy/my/lib/python2.7/site-packages/IPython/core/displayhook.pyc in write_format_data(self, format_dict, md_dict)
    172         # newline, even if all the prompt separators are ''. This is the
    173         # standard IPython behavior.
--> 174         result_repr = format_dict['text/plain']
    175         if '\n' in result_repr:
    176             # So that multi-line strings line up with the left column of

KeyError: 'text/plain'

Well that's because it is abstract class, and doesn't have all the methods. So, I think I will need to define printers explicitly.

Copy link
Member

Choose a reason for hiding this comment

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

But no one should ever be creating instances of SeqExpr - that's just a base class. Not handling that case is fine, as it should never occur (correct me if I'm wrong).

Copy link
Member Author

Choose a reason for hiding this comment

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

Well from user point of view it should never occur. But from a developer point of view, it will become a headache if everytime you initialize SeqExpr in isympy shell and you get a big error. I did have the case, when I had to initialize it, for argument checking. So, I think it's not a good idea.

Copy link
Member

Choose a reason for hiding this comment

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

The solution to this is not to use isympy for debugging the code then. The normal string printer works just fine.

if self._use_unicode:
dots = u("\N{HORIZONTAL ELLIPSIS}")
else:
dots = '...'

if s.start is S.NegativeInfinity:
stop = s.stop
printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2),
s.coeff(stop - 1), s.coeff(stop))
elif s.stop is S.Infinity or s.length > 4:
printset = s[:4]
printset.append(dots)
printset = tuple(printset)
else:
printset = tuple(s)
return self._print_list(printset)

_print_SeqPer = _print_SeqFormula
_print_SeqAdd = _print_SeqFormula
_print_SeqMul = _print_SeqFormula

def _print_seq(self, seq, left=None, right=None, delimiter=', ',
parenthesize=lambda x: False):
s = None
Expand Down
83 changes: 82 additions & 1 deletion sympy/printing/pretty/tests/test_pretty.py
Expand Up @@ -6,7 +6,8 @@
Lambda, Le, Limit, Lt, Matrix, Mul, Nand, Ne, Nor, Not, O, Or,
Pow, Product, QQ, RR, Rational, Ray, RootOf, RootSum, S,
Segment, Subs, Sum, Symbol, Tuple, Xor, ZZ, conjugate,
groebner, oo, pi, symbols, ilex, grlex, Range, Contains)
groebner, oo, pi, symbols, ilex, grlex, Range, Contains,
SeqPer, SeqFormula, SeqAdd, SeqMul)
from sympy.functions import (Abs, Chi, Ci, Ei, KroneckerDelta,
Piecewise, Shi, Si, atan2, binomial, catalan, ceiling, cos,
euler, exp, expint, factorial, factorial2, floor, gamma, hyper, log,
Expand Down Expand Up @@ -3099,6 +3100,86 @@ def test_pretty_sets():
assert upretty(Range(-2, -oo, -1)) == ucode_str


def test_pretty_sequences():
s1 = SeqFormula(a**2, (0, oo))
s2 = SeqPer((1, 2))

ascii_str = '[0, 1, 4, 9, ...]'
ucode_str = u('[0, 1, 4, 9, …]')

assert pretty(s1) == ascii_str
assert upretty(s1) == ucode_str

ascii_str = '[1, 2, 1, 2, ...]'
ucode_str = u('[1, 2, 1, 2, …]')
assert pretty(s2) == ascii_str
assert upretty(s2) == ucode_str

s3 = SeqFormula(a**2, (0, 2))
s4 = SeqPer((1, 2), (0, 2))

ascii_str = '[0, 1, 4]'
ucode_str = u('[0, 1, 4]')

assert pretty(s3) == ascii_str
assert upretty(s3) == ucode_str

ascii_str = '[1, 2, 1]'
ucode_str = u('[1, 2, 1]')
assert pretty(s4) == ascii_str
assert upretty(s4) == ucode_str

s5 = SeqFormula(a**2, (-oo, 0))
s6 = SeqPer((1, 2), (-oo, 0))

ascii_str = '[..., 9, 4, 1, 0]'
ucode_str = u('[…, 9, 4, 1, 0]')

assert pretty(s5) == ascii_str
assert upretty(s5) == ucode_str

ascii_str = '[..., 2, 1, 2, 1]'
ucode_str = u('[…, 2, 1, 2, 1]')
assert pretty(s6) == ascii_str
assert upretty(s6) == ucode_str

ascii_str = '[1, 3, 5, 11, ...]'
ucode_str = u('[1, 3, 5, 11, …]')

assert pretty(SeqAdd(s1, s2)) == ascii_str
assert upretty(SeqAdd(s1, s2)) == ucode_str

ascii_str = '[1, 3, 5]'
ucode_str = u('[1, 3, 5]')

assert pretty(SeqAdd(s3, s4)) == ascii_str
assert upretty(SeqAdd(s3, s4)) == ucode_str

ascii_str = '[..., 11, 5, 3, 1]'
ucode_str = u('[…, 11, 5, 3, 1]')

assert pretty(SeqAdd(s5, s6)) == ascii_str
assert upretty(SeqAdd(s5, s6)) == ucode_str

ascii_str = '[0, 2, 4, 18, ...]'
ucode_str = u('[0, 2, 4, 18, …]')

assert pretty(SeqMul(s1, s2)) == ascii_str
assert upretty(SeqMul(s1, s2)) == ucode_str

ascii_str = '[0, 2, 4]'
ucode_str = u('[0, 2, 4]')

assert pretty(SeqMul(s3, s4)) == ascii_str
assert upretty(SeqMul(s3, s4)) == ucode_str

ascii_str = '[..., 18, 4, 2, 0]'
ucode_str = u('[…, 18, 4, 2, 0]')

assert pretty(SeqMul(s5, s6)) == ascii_str
assert upretty(SeqMul(s5, s6)) == ucode_str


def test_pretty_limits():
expr = Limit(x, x, oo)
ascii_str = \
Expand Down
50 changes: 49 additions & 1 deletion sympy/printing/tests/test_latex.py
Expand Up @@ -14,7 +14,8 @@
meijerg, oo, polar_lift, polylog, re, root, sin, sqrt, symbols,
uppergamma, zeta, subfactorial, totient, elliptic_k, elliptic_f,
elliptic_e, elliptic_pi, cos, tan, Wild, true, false, Equivalent, Not,
Contains, divisor_sigma, SymmetricDifference)
Contains, divisor_sigma, SymmetricDifference, SeqPer, SeqFormula,
SeqAdd, SeqMul)

from sympy.abc import mu, tau
from sympy.printing.latex import latex, translate
Expand Down Expand Up @@ -483,6 +484,53 @@ def test_latex_Range():
assert latex(Range(1, 4)) == r'\left\{1, 2, 3\right\}'


def test_latex_sequences():
s1 = SeqFormula(a**2, (0, oo))
s2 = SeqPer((1, 2))

latex_str = r'\left\[0, 1, 4, 9, \ldots\right\]'
assert latex(s1) == latex_str

latex_str = r'\left\[1, 2, 1, 2, \ldots\right\]'
assert latex(s2) == latex_str

s3 = SeqFormula(a**2, (0, 2))
s4 = SeqPer((1, 2), (0, 2))

latex_str = r'\left\[0, 1, 4\right\]'
assert latex(s3) == latex_str

latex_str = r'\left\[1, 2, 1\right\]'
assert latex(s4) == latex_str

s5 = SeqFormula(a**2, (-oo, 0))
s6 = SeqPer((1, 2), (-oo, 0))

latex_str = r'\left\[\ldots, 9, 4, 1, 0\right\]'
assert latex(s5) == latex_str

latex_str = r'\left\[\ldots, 2, 1, 2, 1\right\]'
assert latex(s6) == latex_str

latex_str = r'\left\[1, 3, 5, 11, \ldots\right\]'
assert latex(SeqAdd(s1, s2)) == latex_str

latex_str = r'\left\[1, 3, 5\right\]'
assert latex(SeqAdd(s3, s4)) == latex_str

latex_str = r'\left\[\ldots, 11, 5, 3, 1\right\]'
assert latex(SeqAdd(s5, s6)) == latex_str

latex_str = r'\left\[0, 2, 4, 18, \ldots\right\]'
assert latex(SeqMul(s1, s2)) == latex_str

latex_str = r'\left\[0, 2, 4\right\]'
assert latex(SeqMul(s3, s4)) == latex_str

latex_str = r'\left\[\ldots, 18, 4, 2, 0\right\]'
assert latex(SeqMul(s5, s6)) == latex_str


def test_latex_intervals():
a = Symbol('a', real=True)
assert latex(Interval(0, 0)) == r"\left\{0\right\}"
Expand Down
6 changes: 5 additions & 1 deletion sympy/series/__init__.py
Expand Up @@ -5,7 +5,11 @@
from .gruntz import gruntz
from .series import series
from .residues import residue
from .sequences import (EmptySequence, SeqPer, SeqFormula, sequence, SeqAdd,
SeqMul)

O = Order
Copy link
Member

Choose a reason for hiding this comment

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

Why did you delete this, instead of adding your stuff to it? This controls what's actually imported from the submodules.

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh, a mistake on my part. Will fix this in my next commit.


__all__ = ['gruntz', 'limit', 'series', 'O', 'Order', 'Limit', "residue"]
__all__ = ['Order', 'O', 'limit', 'Limit', 'gruntz', 'series', 'residue',
'EmptySequence', 'SeqPer', 'SeqFormula', 'sequence',
'SeqAdd', 'SeqMul']