deprecate symbolic function call notation

124 views
Skip to first unread message

William Stein

unread,
Nov 7, 2011, 3:00:57 PM11/7/11
to sage-devel
Hi,

Twice in the last day I've hit this deprecation warning due to making
a stupid typo:

sage: d(N) = (1/2)*(N^2-1)(N^2-N)/(N-1) # contains stupid typo
/Users/wstein/sage/install/current/local/lib/python2.6/site-packages/IPython/iplib.py:2073:
DeprecationWarning: Substitution using function-call syntax and
unnamed arguments is deprecated and will be removed from a future
release of Sage; you can use named arguments instead, like EXPR(x=...,
y=...)
exec code_obj in self.user_global_ns, self.user_ns

I've been trying to get rid of this mistake in symbolic calculus since
probably 2007. I say we get rid of it soon, e.g., in sage-4.8 (or
certainly in sage-5.0). It's time for it to go.

-- William

--
William Stein
Professor of Mathematics
University of Washington
http://wstein.org

kcrisman

unread,
Nov 7, 2011, 4:05:04 PM11/7/11
to sage-devel


On Nov 7, 3:00 pm, William Stein <wst...@gmail.com> wrote:
> Hi,
>
> Twice in the last day I've hit this deprecation warning due to making
> a stupid typo:
>
> sage: d(N) = (1/2)*(N^2-1)(N^2-N)/(N-1)       # contains stupid typo
> /Users/wstein/sage/install/current/local/lib/python2.6/site-packages/IPytho n/iplib.py:2073:
> DeprecationWarning: Substitution using function-call syntax and
> unnamed arguments is deprecated and will be removed from a future
> release of Sage; you can use named arguments instead, like EXPR(x=...,
> y=...)
>   exec code_obj in self.user_global_ns, self.user_ns
>
> I've been trying to get rid of this mistake in symbolic calculus since
> probably 2007.   I say we get rid of it soon, e.g., in sage-4.8 (or
> certainly in sage-5.0).  It's time for it to go.

Even though not agreed, I recognize my opinion is in the minority, and
so I've been teaching people to avoid it for at least two years in
seminars/workshops.

But because of that experience, I have a recommendation.

If you open a ticket (or find one) for this, I think that we should
definitely put some easy-to-find documentation (maybe in the top-level
calculus and symbolics pages) that shows how to change "bad old" code,
especially in certain plotting situations, to the "new good" code
style. As well as some nice examples saying, "Until [2011,2012] we
used this, but it no longer works" (with doctest).

This is one of those places where having the automatic testing of
sagenb-type worksheets would be really helpful, because it would
uncover the most typical (ab)use cases. My guess is there are still
people using old ones. For instance, I hadn't taught a particular
course in two years, and discovered lots of them in my plot interacts
- where you need to say

@interact
def _(f=x^2)
g(x) = f
plot(g)

and that is a little weird, but

plot(f)

I think causes this error. (? if I recall correctly - it was
something along these lines but I don't remember for sure)

Anyway, just a recommendation.

- kcrisman

William Stein

unread,
Nov 7, 2011, 4:10:16 PM11/7/11
to sage-...@googlegroups.com

We could make plot continue to work, even after removing calling, by
testing to see if f has exactly one symbolic variable, and if so call
it. There's a huge difference between a mistake like this:

sage: d(N) = (N^2-1)(N^2-N)/(N-1) # note the missing * --
should be (N^2-1)*(N^2-N)/(N-1)

and something like

sage: d = N^2-1
sage: plot(d)

where it is clear what is intended.

-- William

>
> - kcrisman
>
> --
> To post to this group, send an email to sage-...@googlegroups.com
> To unsubscribe from this group, send an email to sage-devel+...@googlegroups.com
> For more options, visit this group at http://groups.google.com/group/sage-devel
> URL: http://www.sagemath.org

Jason Grout

unread,
Nov 7, 2011, 4:45:43 PM11/7/11
to sage-...@googlegroups.com
On 11/7/11 2:00 PM, William Stein wrote:
> Hi,
>
> Twice in the last day I've hit this deprecation warning due to making
> a stupid typo:
>
> sage: d(N) = (1/2)*(N^2-1)(N^2-N)/(N-1) # contains stupid typo
> /Users/wstein/sage/install/current/local/lib/python2.6/site-packages/IPython/iplib.py:2073:
> DeprecationWarning: Substitution using function-call syntax and
> unnamed arguments is deprecated and will be removed from a future
> release of Sage; you can use named arguments instead, like EXPR(x=...,
> y=...)
> exec code_obj in self.user_global_ns, self.user_ns
>
> I've been trying to get rid of this mistake in symbolic calculus since
> probably 2007. I say we get rid of it soon, e.g., in sage-4.8 (or
> certainly in sage-5.0). It's time for it to go.

+1.


FYI, I made this change as part of my in-progress work on polishing up
fast_callable at http://trac.sagemath.org/sage_trac/ticket/5572. That
said, that ticket is on the back-burner for me, so certainly don't wait
for that ticket to finish.

Thanks,

Jason

Burcin Erocal

unread,
Nov 7, 2011, 4:52:56 PM11/7/11
to sage-...@googlegroups.com
On Mon, 7 Nov 2011 12:00:57 -0800
William Stein <wst...@gmail.com> wrote:

> Twice in the last day I've hit this deprecation warning due to making
> a stupid typo:
>
> sage: d(N) = (1/2)*(N^2-1)(N^2-N)/(N-1) # contains stupid typo
> /Users/wstein/sage/install/current/local/lib/python2.6/site-packages/IPython/iplib.py:2073:
> DeprecationWarning: Substitution using function-call syntax and
> unnamed arguments is deprecated and will be removed from a future
> release of Sage; you can use named arguments instead, like EXPR(x=...,
> y=...)
> exec code_obj in self.user_global_ns, self.user_ns
>
> I've been trying to get rid of this mistake in symbolic calculus since
> probably 2007. I say we get rid of it soon, e.g., in sage-4.8 (or
> certainly in sage-5.0). It's time for it to go.

This is #8214:

http://trac.sagemath.org/sage_trac/ticket/8214

It would be great to finally remove this warning and display a helpful
message instead. Unfortunately, I don't have any time to work on this
these days.


Cheers,
Burcin

Jason Grout

unread,
Nov 7, 2011, 4:56:57 PM11/7/11
to sage-...@googlegroups.com


f=x^2
plot(f)

seems to work fine, with no deprecation warnings. I believe there is
some special-case code in plot for variables of one function already
(which really means that there is some special-case code in
fast_callable or fast_float for single-variable plots).

I still think the user should explicitly specify the variable, though, like:

plot(f,x)

or

plot(f,(x,0,1))

That is clearer and more pythonic (explicit better than implicit, etc.)

Thanks,

Jason

kcrisman

unread,
Nov 7, 2011, 5:03:50 PM11/7/11
to sage-devel
As to William and Jason's points about plot, yes, that is true (and
makes sense to me - we don't have to have ONLY one way to do it,
though we don't have to be like Perl either). I'm referring to some
situations where I run into this on worksheets, and I'm sure others do
as well.

Maybe it's just the interact box taking f=x^2 and then having done
f(2)? Anyway, my only point was that there should be some addition to
the documentation on #8214 to warn people in several places they might
look if they get confused, as it is only natural to do

f(2)

expecting 4, the usual counterexamples of why this is horrible
notwithstanding. Most people I know don't seem to read the manual
before playing :)

I've commented on the appropriate ticket and changed its title,
thanks, Burcin, for finding that.

- kcrisman

Michael Orlitzky

unread,
Nov 7, 2011, 7:21:14 PM11/7/11
to sage-...@googlegroups.com
On 11/07/2011 03:00 PM, William Stein wrote:
> Hi,
>
> Twice in the last day I've hit this deprecation warning due to making
> a stupid typo:
>
> sage: d(N) = (1/2)*(N^2-1)(N^2-N)/(N-1) # contains stupid typo
> /Users/wstein/sage/install/current/local/lib/python2.6/site-packages/IPython/iplib.py:2073:
> DeprecationWarning: Substitution using function-call syntax and
> unnamed arguments is deprecated and will be removed from a future
> release of Sage; you can use named arguments instead, like EXPR(x=...,
> y=...)
> exec code_obj in self.user_global_ns, self.user_ns
>
> I've been trying to get rid of this mistake in symbolic calculus since
> probably 2007. I say we get rid of it soon, e.g., in sage-4.8 (or
> certainly in sage-5.0). It's time for it to go.
>

There's a potential problem with piecewise:

$ ./iterated-2d-solution.py
./iterated-2d-solution.py:85: DeprecationWarning: Substitution using


function-call syntax and unnamed arguments is deprecated and will be
removed from a future release of Sage; you can use named arguments
instead, like EXPR(x=..., y=...)

s_a = this_s(terminal)

"this_s" is a piecewise function of x:

Piecewise defined function with 1 parts, [[(0, 0.500000000000000),
4.00000000000000*(x - 0.500000000000000)^2 - 10.1278345910970*(x -
0.500000000000000)*x + 5.78826325138787*x^2]]

But if you name it explicitly,

TypeError: __call__() got an unexpected keyword argument 'x'


Here's another, where it seems to be complaining about a *python* function:

./w3-double_cubic.py:86: DeprecationWarning: Substitution using


function-call syntax and unnamed arguments is deprecated and will be
removed from a future release of Sage; you can use named arguments
instead, like EXPR(x=..., y=...)

p2 = please_substitute_function(2, domain_points, p2, f, cos(x))

This is defined in another file:

def please_substitute_function(max_degree,
points,
expr,
func1,
func2):
...


Even if I change the call to it in w3-double_cubic.py, I get the same error:

./w3-double_cubic.py:85: DeprecationWarning: Substitution using


function-call syntax and unnamed arguments is deprecated and will be
removed from a future release of Sage; you can use named arguments
instead, like EXPR(x=..., y=...)

p1 = please_substitute_function(max_degree=2,
points=domain_points,
expr=p1,
func1=f,
func2=cos(x))


So please don't trade the warning for an error unless you're sure that
there aren't any false positives (i.e. I'm doing something wrong).

kcrisman

unread,
Nov 7, 2011, 9:03:43 PM11/7/11
to sage-devel
> There's a potential problem with piecewise:
>
>   $ ./iterated-2d-solution.py
>   ./iterated-2d-solution.py:85: DeprecationWarning: Substitution using
>   function-call syntax and unnamed arguments is deprecated and will be
>   removed from a future release of Sage; you can use named arguments
>   instead, like EXPR(x=..., y=...)
>     s_a = this_s(terminal)
>
> "this_s" is a piecewise function of x:
>
>   Piecewise defined function with 1 parts, [[(0, 0.500000000000000),
>   4.00000000000000*(x - 0.500000000000000)^2 - 10.1278345910970*(x -
>   0.500000000000000)*x + 5.78826325138787*x^2]]
>
> But if you name it explicitly,
>
>   TypeError: __call__() got an unexpected keyword argument 'x'

So are you saying that Python and Piecewise functions will no longer
behave correctly if this behavior goes from warning to error? It
would be great if you had a "toy" example with full code; maybe there
is a workaround that needs to become standard practice here...

- kcrisman

Michael Orlitzky

unread,
Nov 8, 2011, 9:09:41 AM11/8/11
to sage-...@googlegroups.com
On 11/07/11 21:03, kcrisman wrote:
>
> So are you saying that Python and Piecewise functions will no longer
> behave correctly if this behavior goes from warning to error? It
> would be great if you had a "toy" example with full code; maybe there
> is a workaround that needs to become standard practice here...

For piecewise, the problem and toy example are easy. The first
evaluation gives the warning, the second an error.

$ cat piecewise_test.py
#!/home/mjo/bin/sage

from sage.all import *

x = SR.symbol('x', domain='real')

interval0 = (0, 0.5)
function0 = 4.0*(x - 0.5)**2
f = piecewise([[interval0, function0]])

print "f(1/2):"
print f(1/2)
print ""

print "f(x=1/2):"
print f(x=1/2)
print ""

Michael Orlitzky

unread,
Nov 8, 2011, 9:50:08 AM11/8/11
to sage-...@googlegroups.com
On 11/07/11 21:03, kcrisman wrote:
>
> So are you saying that Python and Piecewise functions will no longer
> behave correctly if this behavior goes from warning to error? It
> would be great if you had a "toy" example with full code; maybe there
> is a workaround that needs to become standard practice here...
>
> - kcrisman
>

Here's an example of the warning on a python function. It's just showing
the warning in the wrong place.

I've commented the point in the function where the warning really gets
thrown, but I can't figure out a way to get rid of the warning and make
the function work at the same time.

I'm aware that my entire approach here is stupid; I'm willing to accept
any replacements that work as well or better =)


$ cat python_function_test.py
#!/home/mjo/bin/sage

from sage.all import *

def please_substitute_function(max_degree, points, expr, func1, func2):
"""
Sage can't substitute_function on an expression with (evaluated)
derivatives.
"""

for degree in range(0, max_degree+1):
for point_idx in range(0, len(points)):
var1, var2 = var('whatever1,whatever2')

deriv1 = SR(0)
if len(func1.variables()) > 0:
var1 = func1.variables()[0]
deriv1 = derivative(func1, var1, degree)

deriv2 = SR(0)
if len(func1.variables()) > 0:
var2 = func2.variables()[0]
deriv2 = derivative(func2, var2, degree)

target = SR(0)
if len(deriv1.variables()) > 0:
# Works, but throws a warning.
target = deriv1(points[point_idx])

# No error, but doesn't work.
# target = deriv1(var1=points[point_idx])

replacement = SR(0)
if len(deriv2.variables()) > 0:
# Works, but throws a warning.
replacement = deriv2(points[point_idx])

# No error, but doesn't work.
# replacement = deriv2(var2=points[point_idx])

expr = expr.substitute_expression(target == replacement)

return expr


x = SR.symbol('x', domain='real')

f = function('f', x)
p1 = f.diff(x)(x = -1)*x**2 + f(x = 1)*x**3

g = function('g', x)
p2 = please_substitute_function(1, [-1,1], p1, f, g)

print "p1:"
print p1
print ""

print "p2:"
print p2
print ""

kcrisman

unread,
Nov 8, 2011, 9:53:53 AM11/8/11
to sage-devel
Note that this goes away if you instead define

sage: f0(x) = 4.0*(x-0.5)^2

(I mean after restarting Sage; the deprecation warning only will show
up once in any case.)

So I'm not sure this is a problem per se, though that doesn't mean
there isn't another problem lurking. I agree that we would have to
make sure people didn't do this, but the documentation for piecewise
functions already expects people to use f(x)= notation, except if
inserted directly in like Piecewise([[(0,1),x^2]]) or something.

> print "f(x=1/2):"
> print f(x=1/2)
> print ""

Hmm, yeah - piecewise functions don't have a subs() method nor do they
allow this notation. That is a separate problem, and it does seem
like a problem, since

sage: g = x^2
sage: g(x=2)
4
sage: g(2)
DeprecationWarning: Subst...

Michael Orlitzky

unread,
Nov 8, 2011, 9:58:29 AM11/8/11
to sage-...@googlegroups.com
On 11/08/11 09:53, kcrisman wrote:
>
> Note that this goes away if you instead define
>
> sage: f0(x) = 4.0*(x-0.5)^2
>
> (I mean after restarting Sage; the deprecation warning only will show
> up once in any case.)

I've got this in a standalone python file, not running through the sage
prompt. Attempting,

f0(x) = ...

will yell at me for trying to evaluate f0, which is undefined at that point.

kcrisman

unread,
Nov 8, 2011, 10:05:57 AM11/8/11
to sage-devel
Ah, that is luckily easy to fix! Just name your file

piecewise_test.sage

and all will be forgiven. Python files are not preparsed, but .sage
files are. You can even do

sage: attach /path/to/piecewise_test.sage

and it should work great.

Michael Orlitzky

unread,
Nov 8, 2011, 10:30:50 AM11/8/11
to sage-...@googlegroups.com
On 11/08/11 10:05, kcrisman wrote:
>
>
> Ah, that is luckily easy to fix! Just name your file
>
> piecewise_test.sage
>
> and all will be forgiven.

I've tried this before, and gave up out of frustration. Most of my code
is stored in different modules and imported into little executable
scripts that either prove or graph something.

This isn't a very good problem report, but "everything gets screwed up"
when you begin importing from other modules that may or may not be
preparsed.

Anyway, in this case, I'd like to define 'f' in one module
(piecewise_data) and import it into the main script (piecewise_test).


$ cat piecewise_data.sage
from sage.all import *

x = SR.symbol('x', domain='real')

interval0 = (0, 0.5)
function0(x) = 4.0*(x - 0.5)**2


f = piecewise([[interval0, function0]])


$ cat piecewise_test.sage
#!/home/mjo/bin/sage

from sage.all import *
from piecewise_data import *

print "f(1/2):"
print f(1/2)
print ""


$ sage piecewise_test.sage
Traceback (most recent call last):
File "piecewise_test.py", line 6, in <module>
from piecewise_data import *
ImportError: No module named piecewise_data


$ mv piecewise_data.sage piecewise_data.py
$ sage piecewise_test.sage
Traceback (most recent call last):
File "piecewise_test.py", line 6, in <module>
from piecewise_data import *
File "/home/mjo/piecewise_data.py", line 6
function0(x) = 4.0*(x - 0.5)**2
SyntaxError: can't assign to function call

kcrisman

unread,
Nov 8, 2011, 11:03:05 AM11/8/11
to sage-devel


On Nov 8, 10:30 am, Michael Orlitzky <mich...@orlitzky.com> wrote:
> On 11/08/11 10:05, kcrisman wrote:
>
>
>
> > Ah, that is luckily easy to fix!  Just name your file
>
> > piecewise_test.sage
>
> > and all will be forgiven.
>
> I've tried this before, and gave up out of frustration. Most of my code
> is stored in different modules and imported into little executable
> scripts that either prove or graph something.

I see, you're not loading or attaching in an active command line
session. Hopefully someone else has an answer for this; I don't use
such scripts, so I am not sure how to/whether one can solve this.

This definitely is an interesting place where not assigning can lead
to problems, though it really has to be the use case where .sage is
not possible to use. I hope someone has a good answer for you!

- kcrisman
Reply all
Reply to author
Forward
0 new messages