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
Implementing Sequences #9435
Conversation
Some quick bikeshedding: "Sequence" is a good name for what you're doing, but the term is already too overloaded with other, inconsistent meanings. I'd stick with "LazyList" or something like that. My knee-jerk reaction was "is it using the standard mechanisms in Python, like Iterators?" |
It's part of my GSoC project, some more details. Well, I will think on the name though. It can be confusing. |
It's part of my GSoC project, some more [details](https://github.com/sympy/sympy/wiki/GSoC-2015-Application-Sartaj-Singh:-Improving-the-series-package-and-limits-in-SymPy).
Ah I see. Laziness is a pretty big thing, as it can have
counterintuitive effects.
For example, it allows infinite lists, which sounds neat until you
realize that comparing infinite lists for equality is undecidable.
From SymPy's perspective, undecidability isn't a big issue, we need to
deal with it anyway. Usually we go the easy route: punt, abort whatever
we're doing, and leave the expression unchanged, try a different
strategy, or do whatever else is the route of least damage.
If your code already does equality testing on infinite lists, you'll
need to guard against infinite iteration/recursion when iterating over
the elements of a series.
|
|
||
O = Order | ||
|
||
__all__ = ['gruntz', 'limit', 'series', 'O', 'Order', 'Limit', "residue"] |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
Looks like a good start! I think you need to think about the design of these classes a little bit more. Specific things:
|
|
return self._eval_coeff(i) | ||
|
||
def _eval_coeff(self, i): | ||
raise NotImplementedError(filldedent(""" The _eval_coeff method should\ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a side note, you can do something like:
some_func("This is a long "
"wrapping string that "
"Python will put together correctly")
so you don't have to deal with dedenting long text
Other small changes: * Got rid of _foo properties (sympy#9435 (comment)) * Other minor changes (Typo and such)
On the basis of suggestions by @jcrist @flacjacket Changes:
|
I have started working on operations now (starting with addition). |
I have implemented |
I have defined multiplication, subtraction. @jcrist @flacjacket |
@@ -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 |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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. 👍
I see |
|
That's reassuring 👍 |
I like option 1, with the step being optional. Then users like @certik can enter in a variable with a range like they do for other functionality (i.e. That said, I'm not sure why we need a step size - what was your use case for this @leosartaj? |
Well sequences are somewhat like
Also, this type of sequences become easy to represent. |
If you feel a step is a good option, I'm fine with that. But consider that your example above is equivalent to:
|
If the step is optional, then I am fine with 1. Sent from my mobile phone.
|
Yes, step is optional. So, I will go with 1. |
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: | ||
it = iter(s) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
never used.
I just noticed you never define methods for string printing of your classes. This results in falling back on the default printer (which is fine in many cases). However, as a general rule, the string printed representation should be runnable code (ideally). This is not the case, due to you storing the args in a different format than they were input: >>> s = SeqFormula((n**2, n), (0, 5))
>>> s
SeqFormula((n**2, n), ([0, 5], 1))
>>> eval(repr(s))
<big error, trimmed traceback>
/home/jimmy/Code/sympy/sympy/core/sympify.py in sympify(a, locals, convert_xor, strict, rational, evaluate)
270
271 if strict:
--> 272 raise SympifyError(a)
273
274 if iterable(a):
SympifyError: SympifyError: [0, 5] Solutions:
Either is fine, although the simpler the string printer the better. With the change in api we discussed above, this may work itself out. |
TL;DR: I'm -1 on adding step size because the general design rule is to
leave out any features that you aren't confident in being used, because
the cost (nonzero) will outweigh the benefit (zero).
Full argument:
Generally speaking, making an API support more facilities always comes
with wins and losses.
1) Win: Some use case that one wants to support.
2) Win: Even with no use case, APIs tend to find their application. So
one can try it out and see whether people start using it. (You need to
instrument the API with usage feedback, else you'll never know whether
this win actually exists.)
3) Loss: More effort to write API-compatible code (i.e. subclasses in
the case of an OO language).
4) Loss: More effort to check for potential incompatibilities with new
extensions.
5) Loss: Higher risk of having to drop an extension because it cannot be
made compatible.
In this context, we have:
1) Nope.
2) Dubious. An easy workaround exists, if the series becomes too
cumbersome people will simply define a symbol and substitute.
3) Given that the Series stuff is new, it's likely that we'll want to
write new subclasses. So we have a tangible loss here.
4) Hard to evaluate, since we have no idea how future extensions might
look like. We should think more about potential extensions (and maybe
use Series in practice), then reevaluate.
5) Essentially the same situation as with (4).
With nonexistent or dubious wins, I'd say that it's not worth even a
potential loss, much less any losses that we don't know how to evaluate yet.
|
@leosartaj please ping me or @jcrist once you update the PR based on the feedback. |
Changes:
|
Overall this looks very good! One new issue I noticed is that you're inheriting from
If we're not going to allow sequences to be part of expressions (I don't think we should), then sequences should be rooted in Other than that, everything looks good! |
""" | ||
return None | ||
|
||
def coeff_mul(self, other): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what is this for? This should be supported by operators, not a special method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried.
>>> sequence(n**2) * 3
sequence(3*n**2) # works
I had trouble
>>> 3 * sequence(n**2)
TyperError
Maybe __rmul__
can be used here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I am not very sure. It may cause some undesired results. Like multiplying sequence
with a Tuple
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this only exists to make __neg__
work (all it's used with, for now), then you can just move this code inside __neg__
, and remove the function. I really think operators should only work between two sequences, and that operations with sympy expressions should fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have had it's use in FourierSeries
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes only multiplying sequences with sequences should be allowed. I have kept this a separate method. It's works like map
. I am having trouble integrating it into __mul__
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it okay, if it's kept separate, and * knows how to multiply sequences with sequences only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, if it's needed elsewhere then it can stay as a method. Perhaps later something prettier can be made.
Changes:
|
Is this okay? @jcrist |
Looks good, merging! |
@leosartaj : can you please add something to the release notes under major changes about the new sequences functionality. Thanks for you work! |
Sure, Thanks! |
A Sequence is finite or infinite lazily evaluated list. Coefficients will only be evaluated when required.
TODO
Ping @jcrist @flacjacket @certik