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

automatically injected function does not work with desolve #15025

Closed
dkrenn opened this issue Aug 9, 2013 · 7 comments
Closed

automatically injected function does not work with desolve #15025

dkrenn opened this issue Aug 9, 2013 · 7 comments

Comments

@dkrenn
Copy link
Contributor

dkrenn commented Aug 9, 2013

The following does not work:

sage: x = var('x')
sage: f = function('y', x)
sage: desolve(diff(y,x)-y == 0,y)
Traceback (click to the left of this block for traceback)
...
TypeError

altough y is automatically injected to the gobal namespace.

This is because y is of the wrong type:

sage: f, type(f)
(y(x), sage.symbolic.expression.Expression)
sage: y, type(y)
(y, sage.symbolic.function_factory.NewSymbolicFunction)                                      

It works with f:

sage: desolve(diff(f,x)-f == 0,f)                                                            
c*e^x

This is confusing, especially, since in the docstring of function under "Note" you can find

The new function is both returned and automatically injected into the global namespace.

Therefore, it is not absurd to assume that this automatically injected variable is the one I want to use, i.e. the one you would get by y = function('y', x) (similar to the var-command).

(If this is behavior of function is (really) on purpose, then at least the error message of desolve should be more clearifying and give a hint.)

Component: symbolics

Keywords: desolve function

Reviewer: Dima Pasechnik

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

@dkrenn dkrenn added this to the sage-6.1 milestone Aug 9, 2013
@nbruin
Copy link
Contributor

nbruin commented Aug 10, 2013

comment:1

It seems what gets injected and what gets returned is always an issue. On top level,

x = var('x')

is redundant: var('x') already injects the binding. On the other hand,

t = SR.var('t')

is not redundant because the methods on SR do not have injection side effects.

Looking at the side-effect free methods:

sage: from sage.symbolic.function_factory import function as new_function
sage: new_function('g')
g
sage: new_function('g',x)
g(x)
sage: type(new_function('g'))
sage.symbolic.function_factory.NewSymbolicFunction
sage: type(new_function('g',x))
sage.symbolic.expression.Expression

you see the design problem: The routine that constructs new symbolic functions creates entirely different objects depending on the arguments given.

A NewSymbolicFunction is really a different kind of object: it goes into the "operator" slot of symbolic expressions:

sage: (y(x)).operator()
y
sage: (2*x).operator()
<function operator.mul>

I understand how the shorthand new_function('f',x) was considered convenient, but it really muddles the interface and it's only one character shorter than the unambiguous new_function('f')(x).

The confusion is compounded by the top-level function which does inject the function into the global namespace as well, but both function('f') and function('f',x) inject the same thing into the global namespace: the NewSymbolicFunction. It has to do that because after typing either, one would expect f(x) to work. But it does raise the expectation that after declaring function('f',x), the system would somehow know that even the bare function f has something to do with x. It doesn't:

sage: var('t')
t
sage: function('f',t)
f(t)
sage: f.number_of_arguments()
0
sage: f.variables()
()
sage: f.default_variable()
x

You would get the same results from function('f').

For the problem at hand in this ticket: The problem is that desolve really wants a symbolic expression, and that there's no good way of turning a bare function into a symbolic expression: It might try

f( *(f.default_variable() for i in range(f.number_of_arguments())))

but you'll quickly see why that's a senseless try.

IN SHORT:

  • The interface for function leads to wrong expectations by the user
  • The writer of the documentation of function was equally confused
  • desolve should return a more informative error message when the given argument cannot be turned into a symbolic expression.

@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
@sagetrac-tmonteil
Copy link
Mannequin

sagetrac-tmonteil mannequin commented Jan 30, 2015

comment:5

A similar problem was just hit on this ask question.

The bug is about wrong variable injection (the value injected into the Python variable does not correspond to the returned value, while it is claimed), not about desolve:

sage: z = function('y', x)
sage: y
y
sage: z
y(x)
sage: y == z
False
sage: type(y)
<class 'sage.symbolic.function_factory.NewSymbolicFunction'>
sage: type(z)
<type 'sage.symbolic.expression.Expression'>

Besides fixing this bug, i have nothing against removing automatic variable injection from Sage (which seems to concern only var() and function()), since it creates a lot of confusion between symbolic and Python variables among new users, for example we can see a lot of var('n') ; n=2 on ask.sagemath.org, as if var() was a kind of variable declaration.

As for the NewSymbolicFunction vs Expression issue depending on the arguments of function(), our options are:

  • create two distinct Python functions for the two situations,
  • deprecate the use of function('y', x),
  • do not touch anything and provide a better documentation in the function() function.

I like the second one since it goes towards better consistency. But, as for removing the ugly var() (or even the ugly RR that breaks the RDF, RIF, RLF naming scheme and causes meaningless discussions about whether Infinity or NaN belong to it), i expect not everyone to agree, even if this would help newcomers to grasp Sage's logic.

@rwst
Copy link

rwst commented Jan 30, 2015

comment:6

See also #17447, #14270

FWIW, in Sympy Function creates an UndefinedFunction which is clear enough, and you get simply

In [2]: f = Function('f',x)
...
TypeError: __new__() takes exactly 2 arguments (3 given)

@sagetrac-tmonteil
Copy link
Mannequin

sagetrac-tmonteil mannequin commented Jan 30, 2015

comment:7

Thanks for the pointers !

@rwst
Copy link

rwst commented Mar 19, 2016

comment:8

I think it's a duplicate of #17701 (ready for review). True?

@rwst rwst removed this from the sage-6.4 milestone Mar 19, 2016
@dimpase
Copy link
Member

dimpase commented Dec 4, 2021

Reviewer: Dima Pasechnik

@dimpase
Copy link
Member

dimpase commented Dec 4, 2021

comment:9

outdated, closing

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

5 participants