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

allow algorithm keyword when calling BuiltinFunction #17531

Closed
rwst opened this issue Dec 20, 2014 · 49 comments
Closed

allow algorithm keyword when calling BuiltinFunction #17531

rwst opened this issue Dec 20, 2014 · 49 comments

Comments

@rwst
Copy link

rwst commented Dec 20, 2014

As per #17489 comment:17 and #17489 comment:23, the ticket should improve the BuiltinFunction class, such that subclassed function classes that have an algorithm=... keyword given via function call will automatically have this keyword inserted into any __evalf__ member function call.

This means the following should be possible without changes to subclassedfunction.__call__:

sage: from sage.symbolic.function import BuiltinFunction
sage: class MyFunction(BuiltinFunction):
....:    def __init__(self):
....:        BuiltinFunction.__init__(self, 'test', nargs=1)
....:    def _evalf_(self, x, **kwds):
....:        algorithm = kwds.get('algorithm', None)
....:        if algorithm == 'algoA':
....:            return 1.0
....:        else:
....:            return 0.0
....:    def _eval_(self, x):
....:         return self._evalf_try_(x)
sage: f = MyFunction()
sage: f(0.0, algorithm='algoA')
1.00000000000000
sage: f(0.0)
0.000000000000000

At the moment, as with all(?) symbolic functions we get

sage: f(x, algorithm='algoB')
TypeError: __call__() got an unexpected keyword argument 'algorithm'
sage: sin(x, algorithm='algoB')
TypeError: __call__() got an unexpected keyword argument 'algorithm'

So the ticket should also give a better error message for existing functions.

#16812 and #17489 depend on this.

CC: @jdemeyer

Component: symbolics

Keywords: symbolic functions

Author: Ralf Stephan

Branch/Commit: u/rws/17531-1 @ b7e88d4

Issue created by migration from https://trac.sagemath.org/ticket/17531

@rwst rwst added this to the sage-6.5 milestone Dec 20, 2014
@rwst

This comment has been minimized.

@rwst rwst changed the title allow algorithm keyword when _call_()ing BuiltinFunction allow algorithm keyword when calling BuiltinFunction Dec 20, 2014
@rwst
Copy link
Author

rwst commented Dec 20, 2014

comment:2

Is there something missing in the example?

sage: f(x)
Traceback (most recent call last):
  File "<ipython-input-10-963bfc488912>", line 1, in <module>
    f(x)
  File "sage/symbolic/function.pyx", line 942, in sage.symbolic.function.BuiltinFunction.__init__ (build/cythonized/sage/symbolic/function.cpp:9902)
    Function.__init__(self, name, nargs, latex_name, conversions,
  File "sage/symbolic/function.pyx", line 110, in sage.symbolic.function.Function.__init__ (build/cythonized/sage/symbolic/function.cpp:3655)
    if not self._is_registered():
  File "sage/symbolic/function.pyx", line 1042, in sage.symbolic.function.BuiltinFunction._is_registered (build/cythonized/sage/symbolic/function.cpp:10966)
    try:
TypeError: expected string or Unicode object, sage.symbolic.expression.Expression found

@jdemeyer
Copy link

comment:3
f = MyFunction()

instead of

f = MyFunction

Also, __evalf__ should be _evalf_.

@rwst

This comment has been minimized.

@rwst
Copy link
Author

rwst commented Dec 21, 2014

comment:5

Isn't this a bug? Hold as no effect:

sage: from sage.symbolic.function import BuiltinFunction
sage: class MyFunction(BuiltinFunction):
....:    def __init__(self, name):
....:        BuiltinFunction.__init__(self, name, nargs=1)
....:    def _evalf_(self, x, parent=None, algorithm=None):
....:        print algorithm
....:        return x
sage: f = MyFunction('f')
sage: ex = f(0.0, algorithm='algoA', hold=True); ex
algoA
0.000000000000000

sage: sin(0.0, hold=True)
sin(0.000000000000000)

@rwst
Copy link
Author

rwst commented Dec 22, 2014

@rwst
Copy link
Author

rwst commented Dec 22, 2014

Changed branch from u/rws/allow_algorithm_keyword_when_calling_builtinfunction to none

@rwst

This comment has been minimized.

@rwst
Copy link
Author

rwst commented Dec 22, 2014

@rwst
Copy link
Author

rwst commented Dec 22, 2014

New commits:

eaed76a17531: add _algorithm field to cdef class Function

@rwst
Copy link
Author

rwst commented Dec 22, 2014

Author: Ralf Stephan

@rwst
Copy link
Author

rwst commented Dec 22, 2014

Commit: eaed76a

@rwst
Copy link
Author

rwst commented Dec 22, 2014

comment:9

This means that any function now accepts the algorithm keyword which is better than any error message IMHO.

sage: sin(x, algorithm='algoB')
sin(x)

@rwst
Copy link
Author

rwst commented Dec 22, 2014

comment:10

Replying to @rwst:

Isn't this a bug? Hold as no effect:

I'll include a fix for this in #17489.

@kcrisman
Copy link
Member

comment:11
sage: sin(x, algorithm='algoB')
sin(x)

General Sage behavior is to raise some sort of not implemented error or something "unknown algorithm" - we do this in a number of contexts.

@rwst
Copy link
Author

rwst commented Dec 23, 2014

comment:12

Replying to @kcrisman:

sage: sin(x, algorithm='algoB')
sin(x)

General Sage behavior is to raise some sort of not implemented error or something "unknown algorithm" - we do this in a number of contexts.

Actually, the sin function has no behaviour specified for the algorithm keyword and so, the outcome is undefined, meaning it could be either way. Certainly no such convention exists in the documentation. Pragmatically, it would be overkill to implement an algorithm registry for this reason.

@kcrisman
Copy link
Member

comment:13

Well, right, in this case it should just say "undefined keyword" or something!

@rwst
Copy link
Author

rwst commented Dec 25, 2014

comment:14

Replying to @kcrisman:

Well, right, in this case it should just say "undefined keyword" or something!

If you so insist, please help with the following design decision. We could

  • A) add a dictionary to the base class (Function) containing names of algorithms. The user (who writes subclasses of Function) may register names through subclass initialization. Unregistered names given in a __call__ argument result in error.
  • B) make available the algorithm keyword only in a specific subclass of Function. The user would inherit from this subclass. Other existing classes retain their previous behaviour. The user is responsible to give an error in his class for unknown algorithms.
  • C) disallow the algorithm keyword completely from any __call__ method of Function or its subclasses. This means that the end user cannot say factorial(10^6, algorithm=...) but should be able to say f(10^6, hold=True).n(algorithm=...). The function creator is responsible to give an error in his class for unknown algorithms.

Granted, C does make some sense in that all numeric issues are moved into _evalf_, and it works around shortfalls of A or B. But the end user will hate it. With A, there is additional code (clutter) in Function and the subclass must register its algorithm names. With B, it's not a general Function-wide solution.

EDIT: C does not make sense with functions returning int or polynomials and having different algorithms, unless the meaning of f in evalf or 'numerical approximation' is stretched beyond repair.

See also #15200 where Jeroen argues for hardcoding a few backend choices.

#17489 depends on this.

@rwst
Copy link
Author

rwst commented Feb 2, 2015

comment:15

EDIT: C does not make sense with functions returning int or polynomials and having different algorithms, unless the meaning of f in evalf or 'numerical approximation' is stretched beyond repair.

Nevertheless, C seems best.

@kcrisman
Copy link
Member

kcrisman commented Feb 3, 2015

comment:16

If you so insist, please help with the following design decision.

Hmm. I do kind of like A), actually. We already have the dictionary of conversions to other systems (Maxima, Mma, etc.), right? This seems very analogous. But it sounds like you have some concrete examples of some shortcomings. I do agree that the end user might not like C).

@kcrisman
Copy link
Member

kcrisman commented Feb 3, 2015

comment:17

Though maybe if all our other functions have C), as a little browsing suggests, maybe it is okay. For instance, in #17489 I'm not sure Jeroen is suggesting we must do this, just that it should be consistent.

@jdemeyer
Copy link

jdemeyer commented Feb 4, 2015

comment:18

I would propose D:

D) accept any algorithm in __call__, pass algorithm to _evalf_ (and possibly other methods) and do error handling "downstream". For example, the end of Function.__call__ uses Ginac, so there you could add

if algorithm is not None and algorithm != "ginac":
    raise ValueError("unknown algorithm %r for %s"%(algorithm,self))

@rwst
Copy link
Author

rwst commented Feb 5, 2015

comment:19

Ah OK. This can go into GinacFunction.__call__. Maybe I did not consider this solution because factorial, which needs to inherit from GinacFunction (because of #17547), needs the algorithm keyword. But this can be easily and naturally resolved by providing IntegerGinacFunction in #17489 with its own __call__.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Feb 5, 2015

Branch pushed to git repo; I updated commit sha1. New commits:

4bac623Merge branch 'develop' into t/17531/allow_algorithm_keyword_when_calling_builtinfunction
d8f09d017531: add check for any other than 'ginac' algorithm keywords in GinacFunction

@rwst rwst added this to the sage-6.8 milestone Jun 18, 2015
@rwst

This comment has been minimized.

@rwst
Copy link
Author

rwst commented Oct 20, 2015

comment:34

Ping?

@rwst rwst modified the milestones: sage-6.8, sage-6.10 Oct 20, 2015
@rwst
Copy link
Author

rwst commented Oct 24, 2015

@rwst
Copy link
Author

rwst commented Aug 5, 2016

Changed commit from b838310 to acedb88

@rwst
Copy link
Author

rwst commented Aug 5, 2016

comment:36

Seems the recent gamma_inc changes trigger test failures.


New commits:

acedb8817531: allow algorithm keyword when calling BuiltinFunction

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Sep 22, 2016

Changed commit from acedb88 to ebac431

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Sep 22, 2016

Branch pushed to git repo; I updated commit sha1. New commits:

ebac431Merge branch 'develop' into t/17531/17531-1

@rwst
Copy link
Author

rwst commented Sep 22, 2016

comment:38
**********************************************************************
File "src/sage/functions/other.py", line 1020, in sage.functions.other.Function_gamma_inc.__init__
Failed example:
    gamma_inc(CDF(0,1), 3)
Expected:
    0.0032085749933691158 + 0.012406185811871568*I
Got:
    0.003208574993369116 + 0.012406185811871567*I
**********************************************************************
File "src/sage/functions/other.py", line 1117, in sage.functions.other.Function_gamma_inc._evalf_
Failed example:
    gamma_inc(float(-1), float(-1))
Expected:
    (-0.8231640121031085+3.141592653589793j)
Got:
    (-0.8231640121031085-3.141592653589793j)
**********************************************************************
File "src/sage/functions/other.py", line 1119, in sage.functions.other.Function_gamma_inc._evalf_
Failed example:
    gamma_inc(RR(-1), RR(-1))
Expected:
    -0.823164012103109 + 3.14159265358979*I
Got:
    -0.823164012103109 - 3.14159265358979*I
**********************************************************************
File "src/sage/functions/other.py", line 1126, in sage.functions.other.Function_gamma_inc._evalf_
Failed example:
    r = gamma_inc(float(0), float(1)); r
Expected:
    0.21938393439552029
Got:
    0.21938393439552026

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Sep 22, 2016

Changed commit from ebac431 to b7e88d4

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Sep 22, 2016

Branch pushed to git repo; I updated commit sha1. New commits:

b7e88d4add doctest tolerances

@rwst
Copy link
Author

rwst commented Mar 3, 2018

comment:41

I'll close this as wontfix, my argument is in #17489 comment:48

@rwst rwst removed this from the sage-6.10 milestone Mar 3, 2018
@videlec
Copy link
Contributor

videlec commented May 18, 2018

comment:42

closing positively reviewed duplicates

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

No branches or pull requests

4 participants