Adds limit(expr, v, a) syntax#39812
Conversation
|
Hello, @vincentmacri, @nbruin,
Thanks, |
| from sage.misc.latex import latex | ||
| from sage.misc.parser import Parser, LookupNameMaker | ||
| from sage.structure.element import Expression | ||
| from sage.symbolic.expression import Expression |
There was a problem hiding this comment.
Why this import? It shadows the one above. Figure out which one you need (why not the one that was already there?) and remove the other.
There was a problem hiding this comment.
yes you right, the second import just overwrites the 1st one, made the necessary changes
Thanks,
There was a problem hiding this comment.
sage.structure.element.Expression and sage.symbolic.expression.Expression aren't the same. Do you have a reason to change which one is imported here? There was probably a good reason why the code here originally imported the abstract base class rather than the concrete one.
There was a problem hiding this comment.
This still needs addressing
There was a problem hiding this comment.
okay, i guess i probably get this now, since the limit function is operating on symbolic expressions (converted via SR), so the abstract base class is probably sufficient, am i right?
28b5916 to
f468ab1
Compare
|
I'll leave commenting on the code itself to @nbruin since he wrote the first draft of this. All I'll add is that I find the usage of "new syntax" versus "old syntax" in the docstrings a bit confusing. It makes it sounds like we plan to deprecate the old syntax, which I don't think we do plan on doing (or should plan on doing unless there's a good reason). I'm not sure what terms would be better. Maybe just show examples of both without referring to one as being new or old, and just mention in the examples why the syntax you're adding here is preferred/needed in some situations. For example, when I added additional functionality to the |
|
Hello Vincent, Thanks for your feedback on the documentation. I also think that labeling the syntaxes as "new" and "old" maybe could imply we are deprecating x=a, which isn’t the case—both syntaxes are meant to stay supported, as of now unless( as you said) ...... I just wanted to ask that what should be next course of action ? I am thinking to include something like this in the docstrings: Is this the right way of representation? Thanks, |
No, just be neutral: There are two ways of invoking limit. One can write |
05b3f07 to
e806bf7
Compare
|
I have made the necessary changes to the doctests and added examples where necessary, can you please review it. |
|
@nbruin any other feedback regarding the code? |
| is_getitem = hasattr(v.operator(), '__name__') and v.operator().__name__ == '__getitem__' | ||
| if not (is_getitem and v.operands()): | ||
| # If it’s not an indexed variable, checking if it’s numeric | ||
| if v.is_numeric(): |
There was a problem hiding this comment.
certainly not necessary to further differentiate if you know you're going to raise an error
| if not (is_getitem and v.operands()): | ||
| # If it’s not an indexed variable, checking if it’s numeric | ||
| if v.is_numeric(): | ||
| raise TypeError(f"Limit variable must be a variable, not a constant number: {v}") |
There was a problem hiding this comment.
Just raise a more generic message here. You don't need to give the value that is causing the error. That's in the backtrace.
| try: | ||
| a = SR(a) | ||
| except TypeError: | ||
| raise TypeError(f"Cannot convert limit point to symbolic ring: {a}") |
There was a problem hiding this comment.
just let SR(a) raise the error.
| @@ -1498,38 +1699,53 @@ def mma_free_limit(expression, v, a, dir=None): | |||
|
|
|||
| EXAMPLES:: | |||
There was a problem hiding this comment.
My expertise does not extend to mma_free_limit so I cannot review that code.
e806bf7 to
40a04c1
Compare
|
I've applied the suggested changes from the latest review.
Everything has now been updated as suggested. Do you have any further feedback? |
|
@vincentmacri any other feedback from your side ,? |
nbruin
left a comment
There was a problem hiding this comment.
Please make sure you address all concerns. I think I have reflagged issues that I flagged before and that did not receive a response.
If you disagree with my assessment on any one of the items you can respond with your reasons and then we can take it from there.
| from sage.misc.latex import latex | ||
| from sage.misc.parser import Parser, LookupNameMaker | ||
| from sage.structure.element import Expression | ||
| from sage.symbolic.expression import Expression |
There was a problem hiding this comment.
This still needs addressing
|
|
||
| if len(args) == 2: # Syntax: limit(ex, v, a, ...) | ||
| if kwargs: # Cannot mix positional v, a with keyword args | ||
| raise ValueError(f"Use either limit(expr, v, a, ...) or limit(expr, v=a, ...) syntax. " |
There was a problem hiding this comment.
Error message should be an uncapitalized phrase describing the problem; not advice. So:
'''
Cannot mix positional specification of limit variable and point with keyword variable arguments
'''
No need for arguments in message: those can be obtained from traceback.
I don't think advice of the form Use either ... or ... is necessary here. Any advice would go after the primary error message.
| elif len(args) == 0: # Potential syntax: limit(ex, v=a, ...) or limit(ex) | ||
| if len(kwargs) == 1: | ||
| k, = kwargs.keys() | ||
| if not isinstance(k, str): |
There was a problem hiding this comment.
this test is not required:
sage: def f(*args,**kwargs): return args, kwargs
sage: f(**{10:1})
TypeError: keywords must be strings
| k, = kwargs.keys() | ||
| if not isinstance(k, str): | ||
| raise ValueError(f"Invalid variable specification in keyword argument: {k} (must be a string)") | ||
| try: |
There was a problem hiding this comment.
no need to guard with try. Just let error propagate.
|
|
||
| # Ensuring v is a symbolic expression | ||
| if not isinstance(v, Expression): | ||
| try: |
There was a problem hiding this comment.
no need to guard with "try". Just let it raise on error by itself
| # Ensuring v is a symbolic expression | ||
| if not isinstance(v, Expression): | ||
| try: | ||
| v = SR(v) |
There was a problem hiding this comment.
create what you need: use
v=SR.symbol(v)
instead.
There was a problem hiding this comment.
@nbruin
This approach is creating an Error:
For the call
limit(x^2 + 5, 5, 10):
v = 5 is an integer, not an instance of Expression
SR.symbol(v) is called with v = 5, but SR.symbol() expects a string to create a symbolic variable. Passing integer like 5 causes a
TypeError: expected string or bytes-like object, got 'sage.rings.integer.Integer'.
I think this error is occuring because the code assumes v can be converted to a symbolic variable directly, but a constant like 5 isn’t a valid limit variable, limits must be taken with respect to a variable (e.g., x), not a constant,
its working fine with this approach:
# Ensuring v is a symbolic expression and a valid limit variable
if not isinstance(v, Expression):
v = SR(v)
if not v.is_symbol():
raise TypeError("limit variable must be a variable, not a constant")
| v = var(k) | ||
| a = argv[k] | ||
| # Check if v is a valid limit variable | ||
| if not v.is_symbol() and v.is_constant(): |
There was a problem hiding this comment.
you will have a symbol here with the change above, so no reason to check
40a04c1 to
8858361
Compare
|
@nbruin does everything looks good now? |
nbruin
left a comment
There was a problem hiding this comment.
OK that looks fine now. I did find it painful in the review process to not have the comments and markings from the previous review available. Part of that might be github's interface. Another component is that you squash your commits in a forced push, destroying history. It might be better to just make successive commits. If you really want to squash before merge, you could squash at the very end to make a branch with a different (more concise) history but with the same effect on the tree.
|
@nbruin , thanks so much for reviewing the PR thoroughly and providing detailed feedback. Regarding the comment on squashing commits with a forced push: I initially thought that working alone on the branch wouldn't be an issue, but I see how it complicates code review. I'll adjust my approach and make successive commits going ahead Thanks again! |
8858361 to
e74d80f
Compare
|
hello, @roed314 can you review and run the workflows if possible, |
|
Done. It still looks like there's something strange going on with force pushes (if you look at the Files Changed you'll see a bunch of changes that are just 10.6 vs 10.6.rc1). |
|
Documentation preview for this PR (built with commit ec6e145; changes) is ready! 🎉 |
| The positional `limit(expr, v, a)` syntax is particularly useful when | ||
| the limit variable `v` is an indexed variable or another expression | ||
| that cannot be used as a keyword argument (fixes :issue:`38761`):: |
There was a problem hiding this comment.
| The positional `limit(expr, v, a)` syntax is particularly useful when | |
| the limit variable `v` is an indexed variable or another expression | |
| that cannot be used as a keyword argument (fixes :issue:`38761`):: | |
| The positional ``limit(expr, v, a)`` syntax is particularly useful | |
| when the limit variable ``v`` is an indexed variable or another | |
| expression that cannot be used as a keyword argument | |
| (fixes :issue:`38761`):: |
When referring to code, typeset it with two ticks (code) rather than one tick (LaTeX).
There was a problem hiding this comment.
You can see here how the formatting will look in the documentation: https://doc-pr-39812--sagemath.netlify.app/html/en/reference/calculus/sage/calculus/calculus#sage.calculus.calculus.limit
|
I have no idea why giac broke here, nothing you did should be causing this issue as far as I can tell. My best guess is some kind of circular import nonsense. I think I have a possible workaround though. Right now the code calls giac by (attempting to) import |
| a = a._mathematica_init_() | ||
|
|
||
| try: | ||
| math_expr = expression._mathematica_().name() |
There was a problem hiding this comment.
this whole routine needs to be reverted.
On a system that does not have mathematica installed, _mathematica_() raises an error, whereas _mathematica_init_() doesn't. This routine should be making a web request. It should not be trying to run mathematica locally.
I'm pretty sure that all edits made to this routine are erroneous. They are certainly outside the stated scope of the pull request. If there is a change to be made to mma_free_limit it needs to happen on a different pull request.
thanks for spotting the error, looking into it now. |
The |
But I agree with @nbruin, leave the changes to |
|
I think the error with @orlitzky do you have any ideas? Does this code need to change to use the giac interface instead of the giac lib? |
|
I think instead of |
b42232e to
dba0423
Compare
|
doing this only eliminates the giac failure, but the ones related to fricas still exists, my bad, I by mistake force pushed T_T |
vincentmacri
left a comment
There was a problem hiding this comment.
Looks good, one minor nitpick that you can take or leave.
Co-authored-by: Vincent Macri <vincent.macri@ucalgary.ca>
|
@vincentmacri this is so strange, before incorporating your suggestion all the CIs successfully passed, now one of the CIs is failing, and i don't think that this is anything related to your suggestion that i committed? could there be any problem with the CIs ? do we need to run them again? |
I think it is a problem with the CI. You can try running that test locally with |
This reverts commit 182ece1.
|
The CI hiccup seems to have resolved itself. I'm OK with the present state: |
|
Thank you, @nbruin for all the intense code reviews and feedbacks, and thanks to @vincentmacri and @dimpase for all the guidance and your time. I've learned a lot through this PR. |
sagemathgh-39812: Adds limit(expr, v, a) syntax Implemented the limit(expr, variable, value) positional syntax to allow limits with respect to indexed variables or other variables not usable as keyword arguments. Also, Updated the documentation and added doctests for the new syntax and associated error handling. Ensuring code coverage for the new argument parsing. Fixes sagemath#38761 by allowing limits to be taken with respect to indexed variables like x[0] or other symbolic expressions not usable as keyword arguments. While testing, the tests passed except the optional fricas ones that were failing before too. <!-- ^ Please provide a concise and informative title. --> <!-- ^ Don't put issue numbers in the title, do this in the PR description below. --> <!-- ^ For example, instead of "Fixes sagemath#12345" use "Introduce new method to calculate 1 + 2". --> <!-- v Describe your changes below in detail. --> <!-- v Why is this change required? What problem does it solve? --> <!-- v If this PR resolves an open issue, please link to it here. For example, "Fixes sagemath#12345". --> ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [x] The description explains in detail what this PR is about. - [x] I have linked a relevant issue or discussion. - [x] I have created tests covering the changes. - [ ] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies Got the idea and direction of fixing the issue and the link to the relevant conversations in the given PR: sagemath#38780 <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - sagemath#12345: short description why this is a dependency --> <!-- - sagemath#34567: ... --> URL: sagemath#39812 Reported by: Ashutosh Rajora Reviewer(s): Ashutosh Rajora, Dima Pasechnik, nbruin, Vincent Macri
Implemented the limit(expr, variable, value) positional syntax to allow limits with respect to indexed variables or other variables not usable as keyword arguments.
Also, Updated the documentation and added doctests for the new syntax and associated error handling. Ensuring code coverage for the new argument parsing.
Fixes #38761 by allowing limits to be taken with respect to indexed variables like x[0] or other symbolic expressions not usable as keyword arguments.
While testing, the tests passed except the optional fricas ones that were failing before too.
📝 Checklist
⌛ Dependencies
Got the idea and direction of fixing the issue and the link to the relevant conversations in the given PR: #38780