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

Implementing Sequences #9435

merged 19 commits into from Jun 14, 2015

Conversation

leosartaj
Copy link
Member

A Sequence is finite or infinite lazily evaluated list. Coefficients will only be evaluated when required.

TODO

  • SeqBase Class (abstract class)
  • EmptySequence
  • SeqExpr class (SeqPer, SeqFunc, SeqFormula inherit from it)
  • SeqPer class
  • SeqFormula class
  • SeqFunc class
  • Wrapper function for the above sequences
  • Implement SeqExprOp class
  • Term-wise Addition/Subtraction
  • Term-wise Multiplication
  • printing

Ping @jcrist @flacjacket @certik

@toolforger
Copy link
Contributor

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.
I'm not going to insist on that though.

My knee-jerk reaction was "is it using the standard mechanisms in Python, like Iterators?"
Then I saw it's using generators.
I'd like somebody with a higher Python Iterators belt than mine check whether this is typical Python idioms. Not because that's better or anything, but because that would make make it easier for future maintainers if it's following typical Python patterns.

@leosartaj
Copy link
Member Author

It's part of my GSoC project, some more details. Well, I will think on the name though. It can be confusing.

@toolforger
Copy link
Contributor

toolforger commented May 27, 2015 via email


O = Order

__all__ = ['gruntz', 'limit', 'series', 'O', 'Order', 'Limit', "residue"]
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.

@jcrist
Copy link
Member

jcrist commented May 28, 2015

Looks like a good start! I think you need to think about the design of these classes a little bit more. Specific things:

  1. What should be allowed in args for each type of Sequence. How should these args be ordered? Note that all args should (ideally) be sympy objects, and be hashable.
  2. What inputs should be allowed for each type of Sequence?
  3. What validation needs to be done for each type of Sequence to ensure no invalid state is possible?
  4. How can we share as much functionality between these classes as possible?

@leosartaj
Copy link
Member Author

  1. I have followed the design, that for every sequence, there will be first a generator(generates the sequence) and second the interval. Do you see any problems with this design? Well, I have tried to stick with all args being Sympy objects.
  2. Each sequence allows a generator and an interval only. Generator can be different for different sequences. Though, interval has a consistent structure throughout.
  3. I will work more on the validation part.
  4. For this purpose, I decided to create SeqExpr, so that common stuff can be abstracted out.

return self._eval_coeff(i)

def _eval_coeff(self, i):
raise NotImplementedError(filldedent(""" The _eval_coeff method should\
Copy link
Member

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

leosartaj added a commit to leosartaj/sympy that referenced this pull request May 28, 2015
Other small changes:
* Got rid of _foo properties
(sympy#9435 (comment))
* Other minor changes (Typo and such)
@leosartaj
Copy link
Member Author

On the basis of suggestions by @jcrist @flacjacket

Changes:

  • Implemented a wrapper function that returns appropriate sequence.
  • Improved validation of arguments (hopefully)
  • Got rid of _foo properties
  • Minor changes(typo and such)

@leosartaj
Copy link
Member Author

I have started working on operations now (starting with addition).

@jcrist jcrist added the GSoC label May 28, 2015
@leosartaj
Copy link
Member Author

I have implemented SeqAdd class. Addition is now supported. Though subtraction is still not. I have not yet implemented negation. Have a look @jcrist @flacjacket. Suggestions welcome.

@leosartaj
Copy link
Member Author

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
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. 👍

@leosartaj
Copy link
Member Author

I see sequences is a name already taken up and used in python a lot, in a different sense. I think we should change the name to maybe Streams? Suggestion? @flacjacket @jcrist @toolforger

@jcrist
Copy link
Member

jcrist commented Jun 1, 2015

Sequence is fine. It has a different meaning in python, but it also has a specific mathematical meaning - which is what we're implementing here. Streams would be a bad choice IMO. I wouldn't worry about it.

@leosartaj
Copy link
Member Author

That's reassuring 👍

@jcrist
Copy link
Member

jcrist commented Jun 6, 2015

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. (x, 0, 10)), but can also add a step if needed. I like enclosing the whole variable, range, and step as one object, as they're related. Having the step be its own parameter seems awkward and unintuitive.

That said, I'm not sure why we need a step size - what was your use case for this @leosartaj?

@leosartaj
Copy link
Member Author

Well sequences are somewhat like Range. Range does provide an option for step size. So, I also did.

>>> SeqFormula(n**2, (0, oo, 2))
[0, 4, 16, 36, ...]

Also, this type of sequences become easy to represent.

@jcrist
Copy link
Member

jcrist commented Jun 6, 2015

If you feel a step is a good option, I'm fine with that. But consider that your example above is equivalent to:

>>> SeqFormula((2*n)**2, (n, 0, oo))
[0, 4, 16, 36, ...]

@certik
Copy link
Member

certik commented Jun 6, 2015

If the step is optional, then I am fine with 1.

Sent from my mobile phone.
On Jun 6, 2015 9:16 AM, "Jim Crist" notifications@github.com wrote:

I like option 1, with the step being optional. Then users like @certik
https://github.com/certik can enter in a variable with a range like
they do for other functionality (i.e. (x, 0, 10)), but can also add a
step if needed. I like enclosing the whole variable, range, and step as one
object, as they're related. Having the step be its own parameter seems
awkward and unintuitive.

That said, I'm not sure why we need a step size - what was your use case
for this @leosartaj https://github.com/leosartaj?


Reply to this email directly or view it on GitHub
#9435 (comment).

@leosartaj
Copy link
Member Author

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)
Copy link
Member

Choose a reason for hiding this comment

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

never used.

@jcrist
Copy link
Member

jcrist commented Jun 6, 2015

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:

  1. Add methods to the string printer
  2. Store your args identically to their inputs

Either is fine, although the simpler the string printer the better. With the change in api we discussed above, this may work itself out.

@toolforger
Copy link
Contributor

toolforger commented Jun 6, 2015 via email

@certik
Copy link
Member

certik commented Jun 9, 2015

@leosartaj please ping me or @jcrist once you update the PR based on the feedback.

@certik certik added the PR: author's turn The PR has been reviewed and the author needs to submit more changes. label Jun 9, 2015
@leosartaj
Copy link
Member Author

Changes:

  • Changed the api and made it similar to Sum
  • Removed step
  • Removed SeqFunc(redundant with SeqFormula)

@jcrist @certik @flacjacket

@certik certik added PR: sympy's turn and removed PR: author's turn The PR has been reviewed and the author needs to submit more changes. labels Jun 11, 2015
@jcrist
Copy link
Member

jcrist commented Jun 12, 2015

Overall this looks very good! One new issue I noticed is that you're inheriting from Expr, not Basic. This allows the following to work, due to how python handles operators:

>>> n = symbols('n')
>>> seq = sequence(n**2)
>>> seq + n
< this errors, but with a poor error message >
>>> n + seq
n + SeqFormula(n**2, (n, 0, oo))

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 Basic, not Expr. Some arg checking in SeqAdd and SeqMul to detect non sequences would handle the poor error message issue.

Other than that, everything looks good!

"""
return None

def coeff_mul(self, other):
Copy link
Member

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.

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 tried.

>>> sequence(n**2) * 3
sequence(3*n**2) # works

I had trouble

>>> 3 *  sequence(n**2)
TyperError

Maybe __rmul__ can be used here.

Copy link
Member Author

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.

Copy link
Member

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.

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 have had it's use in FourierSeries.

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 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__.

Copy link
Member Author

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?

Copy link
Member

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.

@leosartaj
Copy link
Member Author

Changes:

  • SeqBase now inherits from Basic
  • Only sequences can be added, subtracted and multiplied.

@jcrist

@leosartaj
Copy link
Member Author

Is this okay? @jcrist

@jcrist
Copy link
Member

jcrist commented Jun 14, 2015

Looks good, merging!

jcrist added a commit that referenced this pull request Jun 14, 2015
@jcrist jcrist merged commit 38d5625 into sympy:master Jun 14, 2015
@jcrist
Copy link
Member

jcrist commented Jun 14, 2015

@leosartaj : can you please add something to the release notes under major changes about the new sequences functionality. Thanks for you work!

@leosartaj
Copy link
Member Author

Sure, Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants