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

Remove function call syntax for symbolic expressions #14270

Closed
ppurka opened this issue Mar 14, 2013 · 58 comments
Closed

Remove function call syntax for symbolic expressions #14270

ppurka opened this issue Mar 14, 2013 · 58 comments

Comments

@ppurka
Copy link
Member

ppurka commented Mar 14, 2013

The function call syntax for symbolic expressions has been deprecated for about 12 years. It is about time it raised some errors. This will prevent people from getting confused because of behavior like this.

See also the threads

Update in 9.4.beta4: The deprecation warning introduced in #5930 was not issued in direct interactive use since Sage 8.4 (despite being doctested):

┌────────────────────────────────────────────────────────────────────┐
│ SageMath version 9.4.beta4, Release Date: 2021-07-01               │
│ Using Python 3.9.5. Type "help()" for help.                        │
└────────────────────────────────────────────────────────────────────┘
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Warning: this is a prerelease version, and it may be unstable.     ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
sage: var('y')
y
sage: a = x+y
sage: a(2, 3)
5
sage: warnings.resetwarnings()
sage: a(2, 3)
/Users/mkoeppe/s/sage/sage-rebasing/worktree-gcc11/local/lib/python3.9/site-packages/IPython/core/interactiveshell.py:3343: 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=...)
See http://trac.sagemath.org/5930 for details.
  exec(code_obj, self.user_global_ns, self.user_ns)
5

(fixed in #32139)

Follow-up: #32227 Deprecate methods arguments (alias: args), number_of_arguments, _fast_callable_ for non-callable symbolic expressions

CC: @nthiery @kini @DaveWitteMorris @nbruin @egourgoulhon

Component: symbolics

Author: Punarbasu Purkayastha, Matthias Koeppe

Branch/Commit: 9891a51

Reviewer: Matthias Koeppe, Travis Scrimshaw

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

@ppurka ppurka added this to the sage-5.11 milestone Mar 14, 2013
@ppurka
Copy link
Member Author

ppurka commented Mar 14, 2013

Author: Punarbasu Purkayastha

@ppurka

This comment has been minimized.

@ppurka
Copy link
Member Author

ppurka commented Mar 15, 2013

Work Issues: fix doctests

@ppurka
Copy link
Member Author

ppurka commented Mar 19, 2013

Changed work issues from fix doctests to fix combinat/tutorial.py

@ppurka
Copy link
Member Author

ppurka commented Mar 19, 2013

comment:3

I am able to fix all the doctests except for the following one in combinat/tutorial.py.

The example which fails seems to make no sense to me. A substitute_function method is being used to substitute a function with a symbolic expression.

sage: C, z = var('C,z');
sage: sys = [ C == z + C*C ]
sage: sol = solve(sys, C, solution_dict=True); sol
[{C: -1/2*sqrt(-4*z + 1) + 1/2}, {C: 1/2*sqrt(-4*z + 1) + 1/2}]
sage: s0 = sol[0][C]; s1 = sol[1][C]

...

sage: C = s0; C
-1/2*sqrt(-4*z + 1) + 1/2

...

sage: equadiff
(4*z - 1)*D[0](C)(z) - 2*C(z) + 1 == 0
sage: Cf = sage.symbolic.function_factory.function('C')
sage: equadiff.substitute_function(Cf, s0)  # Original answer is the deprecation + answer
...
TypeError: %d format: a number is required, not NoneType

Let us try to "fix" this (z is a symbolic variable). Somehow the following works (beats me why it does):

sage: equadiff.substitute_function(Cf(z), s0)
(4*z - 1)*D[0](C)(z) - 2*C(z) + 1 == 0     # OK, so this seems to work

But now the next command in the tutorial gives False instead of True

sage: bool(equadiff.substitute_function(Cf(z), s0))  
False

Why is all this happening? Looking at the documentation of substitute_function shows that it should be used for substituting functions, not anything else

    def substitute_function(self, original, new):
        """
        Returns this symbolic expressions all occurrences of the
        function *original* replaced with the function *new*.

And what exactly are we substituting above?

sage: type(Cf)
sage.symbolic.function_factory.NewSymbolicFunction
sage: type(s0)
sage.symbolic.expression.Expression

We are substituting a symbolic function with a symbolic expression! How was this even working earlier?

What should I do with this portion of the tutorial? Delete this?

@ppurka
Copy link
Member Author

ppurka commented Mar 19, 2013

Apply to devel/sage

@kcrisman
Copy link
Member

comment:4

Attachment: trac_14270-raise_error_on_function-call.patch.gz

Replying to @ppurka:

I am able to fix all the doctests except for the following one in combinat/tutorial.py.

> What should I do with this portion of the tutorial? Delete this?

I'm cc:ing Nicolas, who should know what is going on here.

@kcrisman
Copy link
Member

comment:5

I'd also say that I think the prep tutorial one should still talk about this at some length, to explain (in the event this is done) why this doesn't work, because a lot of people will now and forevermore expect that it will work. Similarly, most of these examples presumably should be moved to the new syntax, perhaps even with an explanatory remark as to exactly why that is the syntax. For instance, how would one do the matrix example h(x) now? We should be careful not to remove anything, just to change how it works to the appropriate way post-this-ticket.

Rant I don't actually want to rehash any more, but put here for completeness:

<rant>
Because distinguishing between a function and a symbolic expression is an unnatural, CS-y thing to do; any symbolic expression is obviously a function of all variables in it, mathematically; for any function with more than one `var` I agree we don't want this (as indeed the example in the prep document points out) but for one-variable expressions (pace Jason, who will immediately ask whether `x+y-y` is one variable) it seems worth the potential for confusion...
</rant>

@ppurka
Copy link
Member Author

ppurka commented Mar 20, 2013

comment:6

Replying to @kcrisman:

I'd also say that I think the prep tutorial one should still talk about this at some length, to explain (in the event this is done) why this doesn't work, because a lot of people will now and forevermore expect that it will work.

IMHO, the people who expect this to still work need to change their code. It has been in deprecated mode for over four years. That's more than enough time to change their habit and old code. I think someone hasn't complained before either because they are complacent or because they don't use this at all.

While teaching a course with Sage, I remember that we ourselves ran into this problem with the students. It was annoying and confusing because we were unaware of the code and how to fix it. We would just ask the students to ignore those warnings. What would a beginner do after defining f(x) = x^2? The most natural thing would be to do f(2) or something similar to "see" that it can actually evaluate. Now imagine the same with f = x^2 and what you get is the deprecation message and then the correct answer. Second time it is evaluated, there is no deprecation message, so a beginner will wonder what just happened in the first invocation. It is not a favorable impression. It gives the impression of a half-done software.

I agree with you that it should be explained in the tutorial that there is a difference between symbolic functions and symbolic expressions and python functions.

@jdemeyer jdemeyer modified the milestones: sage-5.11, sage-5.12 Aug 13, 2013
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.1, sage-6.2 Jan 30, 2014
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.2, sage-6.3 May 6, 2014
@sagetrac-vbraun-spam sagetrac-vbraun-spam mannequin modified the milestones: sage-6.3, sage-6.4 Aug 10, 2014
@rwst

This comment has been minimized.

@rwst
Copy link

rwst commented Feb 1, 2015

comment:12

This is actually the same as #8214, but that has no code, so I'm copying the two links from there to here before declaring it a dupe.

@ppurka
Copy link
Member Author

ppurka commented Feb 1, 2015

comment:13

This ticket is unlikely to get fixed unless someone who knows the code really well addresses comment:3

@nbruin
Copy link
Contributor

nbruin commented Feb 1, 2015

comment:14

Replying to @ppurka:

I am able to fix all the doctests except for the following one in combinat/tutorial.py.

OK, from what you've written down here, I can come up with one way of rewriting the example.

sage: C, z = var('C,z');
sage: sys = [ C == z + C*C ]
sage: sol = solve(sys, C, solution_dict=True); sol
[{C: -1/2*sqrt(-4*z + 1) + 1/2}, {C: 1/2*sqrt(-4*z + 1) + 1/2}]
sage: s0 = sol[0][C]; s1 = sol[1][C]
sage: C = s0; C
-1/2*sqrt(-4*z + 1) + 1/2

I think this should be deleted. Use s0 if you want that and just leave C bound to the variable. It's already bad enough that we need "C as a function" further down.

sage: equadiff
(4*z - 1)*D[0](C)(z) - 2*C(z) + 1 == 0
sage: Cf = sage.symbolic.function_factory.function('C')

Didn't we need Cf before to arrive at equadiff? How did C(z) get into that expression in the first place?

sage: equadiff.substitute_function(Cf, s0)  # Original answer is the deprecation + answer
...
TypeError: %d format: a number is required, not NoneType

I think the following should work (it does in vanilla, without a deprecation warning):

sage: equadiff.substitute_function(Cf, s0.function(z))

Let us try to "fix" this (z is a symbolic variable). Somehow the following works (beats me why it does):

sage: equadiff.substitute_function(Cf(z), s0)
(4*z - 1)*D[0](C)(z) - 2*C(z) + 1 == 0     # OK, so this seems to work

I'm not so sure it "works". It doesn't give an error (which is surprising in its own right; perhaps that should change), but I don't think it gives the same answer. In vanilla:

sage: equadiff.substitute_function(Cf(z), s0)
(4*z - 1)*D[0](C)(z) - 2*C(z) + 1 == 0
sage: equadiff.substitute_function(Cf, s0.function(z))
(4*z - 1)/sqrt(-4*z + 1) + sqrt(-4*z + 1) == 0

But now the next command in the tutorial gives False instead of True

Rightly so, judging from the results above.

Why is all this happening? Looking at the documentation of substitute_function shows that it should be used for substituting functions, not anything else

    def substitute_function(self, original, new):
        """
        Returns this symbolic expressions all occurrences of the
        function *original* replaced with the function *new*.

And what exactly are we substituting above?

sage: type(Cf)
sage.symbolic.function_factory.NewSymbolicFunction
sage: type(s0)
sage.symbolic.expression.Expression

We are substituting a symbolic function with a symbolic expression! How was this even working earlier?

I guess because symbolic expressions were deprecated "functions": you could call then with symbolic arguments and get a symbolic expression, at the cost of a deprecation warning.

What should I do with this portion of the tutorial? Delete this?

No, just do

sage: equadiff.substitute_function(Cf, s0.function(z))

That's probably a useful example to have anyway. It shows how to turn a symbolic expression into a function in a non-ambiguous way, because you need to specify argument order.

@kini

This comment has been minimized.

@mkoeppe
Copy link
Member

mkoeppe commented Jul 24, 2021

comment:44
sage -t --long --random-seed=0 src/sage/calculus/desolvers.py
**********************************************************************
File "src/sage/calculus/desolvers.py", line 1609, in sage.calculus.desolvers.?
Failed example:
    sol=desolve_odeint(f,[0.5,2],srange(0,10,0.1),[x,y])
Exception raised:
    Traceback (most recent call last):
      File "/home/sage-patchbot/sage/local/lib/python3.8/site-packages/sage/doctest/forker.py", line 718, in _run
        self.compile_and_execute(example, compiler, test.globs)
      File "/home/sage-patchbot/sage/local/lib/python3.8/site-packages/sage/doctest/forker.py", line 1137, in compile_and_execute
        exec(compiled, globs)
      File "<doctest sage.calculus.desolvers.?[3]>", line 1, in <module>
        sol=desolve_odeint(f,[RealNumber('0.5'),Integer(2)],srange(Integer(0),Integer(10),RealNumber('0.1')),[x,y])
      File "/home/sage-patchbot/sage/local/lib/python3.8/site-packages/sage/calculus/desolvers.py", line 1726, in desolve_odeint
        return desolve_odeint_inner(ivar)
      File "/home/sage-patchbot/sage/local/lib/python3.8/site-packages/sage/calculus/desolvers.py", line 1679, in desolve_odeint_inner
        desc.append(fast_float(de,*variabs))
      File "sage/ext/fast_eval.pyx", line 1391, in sage.ext.fast_eval.fast_float (build/cythonized/sage/ext/fast_eval.c:11249)
        return fast_callable(f, vars=vars, domain=float,
      File "sage/ext/fast_callable.pyx", line 457, in sage.ext.fast_callable.fast_callable (build/cythonized/sage/ext/fast_callable.c:4734)
        vars = [to_var(var) for var in vars]
      File "sage/ext/fast_callable.pyx", line 456, in sage.ext.fast_callable.fast_callable.to_var (build/cythonized/sage/ext/fast_callable.c:4147)
        return SR.var(var)
      File "sage/symbolic/ring.pyx", line 999, in sage.symbolic.ring.SymbolicRing.var (build/cythonized/sage/symbolic/ring.cpp:11232)
        raise ValueError(f'The name "{s}" is not a valid Python identifier.')
    ValueError: The name "(symbol1790" is not a valid Python identifier.

@mkoeppe
Copy link
Member

mkoeppe commented Jul 25, 2021

Changed dependencies from #32139, #32233 to #32139, #32233, #29738

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jul 25, 2021

Changed commit from 4063e39 to e198c5d

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Jul 25, 2021

Branch pushed to git repo; I updated commit sha1. Last 10 new commits:

ae0a28eExpression.__len__: Deprecate
65881e9Expression.__len__: Update doctest output
5690782ParametrizedSurface3D.__init__: Do not call len on something that could be either a variable or a list/tuple
3575a8fsage.calculus.desolvers.desolve_odeint: Simplify code, avoid calling `__len__` on symbolic expressions
75d7751Merge #32139
4a63e61Trac #29738: update/fix doctest in asymptotics_multivariate_generating_functions.py
e40f9feMerge tag '9.4.beta5' into t/29738/perhaps_symbolic_expressions_should_not_have_a_length
75f6533desolve_odeint: Simplify code
86b0108Expression.number_of_operands, __len__: Update docstrings to use the word 'operands' instead of 'arguments'
e198c5dMerge #29738

@orlitzky
Copy link
Contributor

comment:48

I think this needs a rebase onto rc0? Trac merge failed even though it rebases cleanly.

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Aug 1, 2021

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

9891a51Merge tag '9.4.rc0' into t/14270/remove_function_call_syntax_for_symbolic_expressions

@sagetrac-git
Copy link
Mannequin

sagetrac-git mannequin commented Aug 1, 2021

Changed commit from e198c5d to 9891a51

@mkoeppe
Copy link
Member

mkoeppe commented Aug 3, 2021

Changed dependencies from #32139, #32233, #29738 to none

@mkoeppe
Copy link
Member

mkoeppe commented Aug 3, 2021

Reviewer: Matthias Koeppe, ...

@tscrim
Copy link
Collaborator

tscrim commented Aug 5, 2021

comment:52

We have given people plenty of time to stop using this. Time to bring down the hammer. I am setting this to a positive review, but setting it to 9.5 just to make sure it does not go into the soon-to-be-released 9.4 to get more testing.

@tscrim
Copy link
Collaborator

tscrim commented Aug 5, 2021

Changed reviewer from Matthias Koeppe, ... to Matthias Koeppe, Travis Scrimshaw

@mkoeppe
Copy link
Member

mkoeppe commented Aug 9, 2021

comment:53

Thank you!

@vbraun
Copy link
Member

vbraun commented Aug 29, 2021

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