-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
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
translate abstract functions to Sage #13476
Conversation
No travis log. I restarted the build but it doesn't show here. |
The plotting tests fail under Py3 with:
The reason is the warning |
Please add a test to the sage tests. |
Note to whomever merges this: the sage tests are set to allowed failure in Travis, so you need to check them manually. |
See also https://trac.sagemath.org/ticket/20204 |
That should be it now. |
@rwst can you please resolve merge conflicts. |
@rwst are you still interested in this? |
@timokau this patch to sympy https://github.com/NixOS/nixpkgs/blob/master/pkgs/development/python-modules/sympy/default.nix#L25 in nix break with current master. @rwst still interested in this PR? |
@rswt Are you still interested to work on this PR? |
✅ Hi, I am the SymPy bot (v149). I'm here to help you write a release notes entry. Please read the guide on how to write release notes. Your release notes are in good order. Here is what the release notes will look like: This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.5. Note: This comment will be updated with the latest check if you edit the pull request. You need to reload the page to see it. Click here to see the pull request description that was parsed.
Update The release notes on the wiki have been updated. |
Codecov Report
@@ Coverage Diff @@
## master #13476 +/- ##
=============================================
- Coverage 74.76% 61.964% -12.797%
=============================================
Files 634 634
Lines 165333 165342 +9
Branches 38857 38861 +4
=============================================
- Hits 123604 102453 -21151
- Misses 36309 57050 +20741
- Partials 5420 5839 +419 |
Travis-CI build with sage doesn't produce coverage reports, so the lines in coverage report are red, but those lines are tested. |
sympy/core/function.py
Outdated
@@ -909,6 +922,7 @@ def __new__(mcl, name, bases=(AppliedUndef,), __dict__=None, **kwargs): | |||
__dict__['__module__'] = None | |||
obj = super(UndefinedFunction, mcl).__new__(mcl, name, bases, __dict__) | |||
obj.name = name | |||
obj._sage_ = UndefSage() |
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.
Does this need to be a different instance for each undefined function? As far as I can tell the UndefSage class has no instance data so it can be a singleton class. In fact why isn't it just a property-method using @property
?
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 changed it to a Singleton class.
In fact why isn't it just a property-method using
@property
?
What do you mean by this?
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.
Can we instead define a method like this?
@property
def _sage_(self):
...
It isn't normally necessary to explicitly create a descriptor object.
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.
No, this is a class with AppliedUndef
as a base and therefore its _sage_
is called instead of the method like you mentioned.
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 meant that it's a meta class.
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.
It does seem that way (I'm trying to think of an alternative...)
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.
Btw when I said the class could be a singleton I just meant that it could be like:
class A:
pass
a = A()
...
obj._sage_ = a
rather than using more metaclasses.
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.
Wouldn't that increase import time for sympy?
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 don't see why it would increase import time. Here's a quick test (module t.py
):
from sympy.core.compatibility import with_metaclass
from sympy.core.singleton import Singleton
def f():
class A(with_metaclass(Singleton)):
pass
def g():
class B:
pass
b = B()
Running this with timeit I get:
$ python -m timeit -s 'from t import f, g' 'f()'
1000 loops, best of 5: 222 usec per loop
$ python -m timeit -s 'from t import f, g' 'g()'
50000 loops, best of 5: 9.72 usec per loop
So normal Python classes are 20 times faster than Singleton/metaclass.
The purpose of the Singleton metaclass is to install the class in the singleton registry so it becomes available as e.g. S.Infinity
which isn't what we want 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.
Thanks @oscarbenjamin, I've removed the use of Singleton
metaclass and used the method you proposed.
Looks good. Thanks. |
Thanks @oscarbenjamin for the review |
This finally fixes the conversion of abstract functions to Sage. Reason to do it this way:
When
F=Function('abc')
is called the constructor ofFunction
uses the metaclassUndefFunction
to create a new class with parentAppliedUndef
namedabc
. CallingF._sage_()
will NOT call the_sage_()
member ofAppliedUndef
but tries to callabc._sage_()
which does not exist at installation time. This, however, is not a problem because we can dynamically add a_sage_()
method toabc
on creation ofabc
insideUndefFunction.__new__
. So converting abstract functions works.The problem is that now
F(x)._sage_()
will call the sameabc._sage_()
class method while previously it was referred to the superclass, i.e. theAppliedUndef._sage_()
member function. But_sage_
as class method does not know about the specific instance and its argumentx
!This issue does not contain test code because testing Sage in Travis does not work at the moment and the PR patch is tested in Sage thoroughly, see https://trac.sagemath.org/ticket/20204