Opened 6 years ago

Last modified 4 years ago

#15025 needs_review defect

automatically injected function does not work with desolve

Reported by: dkrenn Owned by:
Priority: major Milestone: sage-duplicate/invalid/wontfix
Component: symbolics Keywords: desolve function
Cc: Merged in:
Authors: Reviewers:
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Description

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.)

Change History (8)

comment:1 Changed 6 years ago by nbruin

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.

comment:2 Changed 6 years ago by vbraun_spam

  • Milestone changed from sage-6.1 to sage-6.2

comment:3 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.2 to sage-6.3

comment:4 Changed 5 years ago by vbraun_spam

  • Milestone changed from sage-6.3 to sage-6.4

comment:5 Changed 5 years ago by tmonteil

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.

comment:6 Changed 5 years ago by rws

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)

comment:7 Changed 5 years ago by tmonteil

Thanks for the pointers !

comment:8 Changed 4 years ago by rws

  • Milestone changed from sage-6.4 to sage-duplicate/invalid/wontfix
  • Status changed from new to needs_review

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

Note: See TracTickets for help on using tickets.