Opened 11 years ago

# Failure with diff(f(x),x).subs(f(x) == g(x))

Reported by: Owned by: gmhossain major sage-8.0 symbolics kcrisman, mjo, eviatarbach, jakobkroeker N/A wrongAnswerMarker

Subject says it all.

Previous (no longer up-to-date) description was:

In computing functional derivative, one needs to vary a functional. For example, in sage-3.4 one can do as follows

```sage: f(x) = function('f',x)
sage: df(x) = function('df',x)
sage: g = f(x).diff(x)
sage: g
diff(f(x), x, 1)
sage: g.subs_expr(f(x)==f(x)+df(x))
diff(f(x) + df(x), x, 1)
```

In new symbolics, if I do the same I get

```sage: g
D(f)(x)
sage: g.subs_expr(f(x)==f(x)+df(x))
D(f)(x)
```

From #11842, the list of what does/doesn't work:

```from sage.all import *

# 1. Fails.
x = var('x')
f = function('f', x)
g = function('g', x)
p = f
print p.substitute_function(f, g) # Outputs "f(x)"

# 2. Fails.
x = var('x')
f = function('f')
g = function('g')
p = f(x)
print p.substitute_function(f(x), g(x)) # Outputs "f(x)"

# 3. Works.
x = var('x')
f = function('f')
g = function('g')
p = f(x)
print p.substitute_function(f, g) # Outputs "g(x)"

# 4. Fails.
x = var('x')
f = function('f')
g = function('g')
p = f(1)
print p.substitute_function(f(1), g(1)) # Outputs "f(1)"

# 5. Works.
x = var('x')
f = function('f')
g = function('g')
p = f(1)
print p.substitute_function(f, g) # Outputs "g(1)"

# 6. Fails.
x = var('x')
f = function('f', x)
g = function('g', x)
p = f.diff()
print p.substitute_function(f, g) # Outputs "D(f)(x)"

# 7. Fails.
x = var('x')
f = function('f', x)
g = function('g', x)
p = f.diff()
print p.substitute_function(f(x), g(x)) # Outputs "D(f)(x)"

# 8. Works.
x = var('x')
f = function('f')
g = function('g')
p = f(x).diff()
print p.substitute_function(f, g) # Outputs "D(g)(x)"

# 9. Fails.
x = var('x')
f = function('f')
g = function('g')
p = f(x).diff()(1)
print p.substitute_function(f(x).diff(), g(x).diff()) # Outputs "D(f)(1)"

# 10. Works..
x = var('x')
f = function('f')
g = function('g')
p = f(x).diff()(1)
print p.substitute_function(f, g) # Prints D(g)(1).
```

### comment:1 Changed 10 years ago by kcrisman

• Report Upstream set to N/A

### comment:2 Changed 9 years ago by mjo

I duped this in #11842. We might be able to make use of the test cases there when this gets fixed.

### comment:5 Changed 8 years ago by mjo

One of the cases in #11842 that used to crash now works, but a lot of them still don't. I updated the list.

### comment:6 Changed 8 years ago by kcrisman

• Description modified (diff)

I feel like if that one is closed, we should have the list here, so I'm updating the description.

### comment:7 Changed 5 years ago by jakobkroeker

• Stopgaps set to todo

### comment:8 Changed 4 years ago by rws

I think these are different issues because `substitute_function` handles a narrowly defined set of cases, and it expects two functions (`f, g, sin`) not expressions (`f(x), diff(f(x),x)`) as function arguments. Cases above that are in the former category:

```sage: f = function('f')(x)
....: g = function('g')(x)
....: df = f(x).diff(x)
sage: f.substitute_function(f,g)
f(x)
sage: f(1).substitute_function(f,g)
f(1)
sage: df.substitute_function(f,g)
diff(f(x), x)
sage: df(1).substitute_function(f,g)
D(f)(1)
```

The problem is that `f` and `g` are not function objects like `sin`. Taking this into account:

```sage: f.substitute_function(f.operator(), g.operator())
g(x)
sage: f(1).substitute_function(f.operator(), g.operator())
g(1)
sage: df.substitute_function(f.operator(), g.operator())
diff(g(x), x)
sage: df(1).substitute_function(f.operator(), g.operator())
D(g)(1)
```

I opened #22401 for this.

### comment:9 Changed 4 years ago by rws

Also, even if `subs` is fixed there is no way atm to get and use `diff(f(x)+g(x),x)`:

```sage: diff(f(x)+g(x),x)
diff(f(x), x) + diff(g(x), x)
sage: diff(f(x)+g(x),x,hold=True)
TypeError: derivative() got an unexpected keyword argument 'hold'
```

`diff` is not a function, although it could well be theoretically:

```sage: diff(f(x),x)
diff(f(x), x)
sage: _._dbgprinttree()
fderivative f @0x34a8c00, hash=0x1023d75fb40091, flags=0xb, nops=1, params=0
x (symbol) @0x2895f10, serial=7, hash=0xe3706ef, flags=0xf, domain=0, iflags=0000000000000000
=====
sage: diff(f(x),x)
diff(f(x), x)
sage: _.operator()
D(f)
sage: type(_)
<class 'sage.symbolic.operators.FDerivativeOperator'>
```

I cannot see why `diff(f(x)+g(x),x,hold=True)` should be supported so I'm not opening a ticket. Just don't expect that as output from a fixed `subs`.

### comment:10 Changed 4 years ago by rws

So, what should work is

```            sage: f = function('f')
sage: g = function('g')
sage: f(x).subs(f(x) == g(x))
g(x)
sage: f(x).subs(f == g)
g(x)
sage: f(x).subs({f : g})
g(x)
sage: df = f(x).diff(x); df
diff(f(x), x)
sage: df.subs(f(x) == g(x))
diff(g(x), x)
sage: df.subs(f == g)
diff(g(x), x)
sage: df.subs(f(x) == f(x) + g(x))
diff(f(x), x) + diff(g(x), x)
sage: df.subs(f == f + g)
diff(f(x), x) + diff(g(x), x)
```

but it mostly doesn't:

```Failed example:
f(x).subs(f == g)
Exception raised:
Traceback (most recent call last):
File "/home/ralf/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 498, in _run
self.compile_and_execute(example, compiler, test.globs)
File "/home/ralf/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 861, in compile_and_execute
exec(compiled, globs)
File "<doctest sage.symbolic.expression.Expression.substitute>", line 1, in <module>
f(x).subs(f == g)
File "sage/symbolic/expression.pyx", line 4961, in sage.symbolic.expression.Expression.substitute (build/cythonized/sage/symbolic/expression.cpp:29715)
g(x)
File "sage/symbolic/expression.pyx", line 348, in sage.symbolic.expression._subs_make_dict (build/cythonized/sage/symbolic/expression.cpp:5364)
raise TypeError(msg.format(s))
TypeError: not able to determine a substitution from False
**********************************************************************
Failed example:
f(x).subs({f : g})
Exception raised:
Traceback (most recent call last):
File "/home/ralf/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 498, in _run
self.compile_and_execute(example, compiler, test.globs)
File "/home/ralf/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 861, in compile_and_execute
exec(compiled, globs)
File "<doctest sage.symbolic.expression.Expression.substitute>", line 1, in <module>
f(x).subs({f : g})
File "sage/symbolic/expression.pyx", line 4971, in sage.symbolic.expression.Expression.substitute (build/cythonized/sage/symbolic/expression.cpp:30001)
diff(f(x), x) + diff(g(x), x)
File "sage/symbolic/expression.pyx", line 2885, in sage.symbolic.expression.Expression.coerce_in (build/cythonized/sage/symbolic/expression.cpp:21682)
return self._parent._coerce_(z)
File "sage/structure/parent_old.pyx", line 241, in sage.structure.parent_old.Parent._coerce_ (build/cythonized/sage/structure/parent_old.c:4949)
return self.coerce(x)
File "sage/structure/parent.pyx", line 1195, in sage.structure.parent.Parent.coerce (build/cythonized/sage/structure/parent.c:11169)
raise TypeError("no canonical coercion from %s to %s" % (parent(x), self))
TypeError: no canonical coercion from <class 'sage.symbolic.function_factory.NewSymbolicFunction'> to Symbolic Ring
**********************************************************************
df.subs(f(x) == g(x))
Expected:
diff(g(x), x)
Got:
diff(f(x), x)
**********************************************************************
df.subs(f == g)
Exception raised:
Traceback (most recent call last):
File "/home/ralf/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 498, in _run
self.compile_and_execute(example, compiler, test.globs)
File "/home/ralf/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 861, in compile_and_execute
exec(compiled, globs)
File "<doctest sage.symbolic.expression.Expression.substitute>", line 1, in <module>
df.subs(f == g)
File "sage/symbolic/expression.pyx", line 4961, in sage.symbolic.expression.Expression.substitute (build/cythonized/sage/symbolic/expression.cpp:29715)
g(x)
File "sage/symbolic/expression.pyx", line 348, in sage.symbolic.expression._subs_make_dict (build/cythonized/sage/symbolic/expression.cpp:5364)
raise TypeError(msg.format(s))
TypeError: not able to determine a substitution from False
**********************************************************************
df.subs(f(x) == f(x) + g(x))
Expected:
diff(f(x), x) + diff(g(x), x)
Got:
diff(f(x), x)
**********************************************************************
df.subs(f == f + g)
Exception raised:
Traceback (most recent call last):
File "/home/ralf/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 498, in _run
self.compile_and_execute(example, compiler, test.globs)
File "/home/ralf/sage/local/lib/python2.7/site-packages/sage/doctest/forker.py", line 861, in compile_and_execute
exec(compiled, globs)
File "<doctest sage.symbolic.expression.Expression.substitute>", line 1, in <module>
df.subs(f == f + g)
TypeError: unsupported operand type(s) for +: 'NewSymbolicFunction' and 'NewSymbolicFunction'
```

### comment:11 follow-up: ↓ 16 Changed 4 years ago by rws

The above consists of three problems. The central one is the failure to `f(x).subs(f(x) == g(x))`; the `diff` case is probably only a result; it looks like this is a Pynac bug, and when fixed there it should be doctested here.

The second is the failure of `f(x).subs({f : g})`. Maybe we can delegate to `substitute_function` if the dict key/val pair consists of function objects.

The third is that `f+g` already bails out. But `SR('f')+SR('g')` does not so this would be a workaround.

### comment:12 Changed 4 years ago by rws

• Milestone set to sage-7.7
• Stopgaps todo deleted
• Summary changed from .subs_expr() method doesn't work for argument of D derivative operator to Failure with f(x).subs(f(x) == g(x))

### comment:13 Changed 4 years ago by rws

• Description modified (diff)

### comment:14 Changed 4 years ago by rws

• Summary changed from Failure with f(x).subs(f(x) == g(x)) to diff(f(x),x).subs(f(x) == g(x))

Nah, it was wrong, only `diff(f(x),x).subs(f(x) == g(x))` doesn't work.

### comment:15 Changed 4 years ago by rws

• Summary changed from diff(f(x),x).subs(f(x) == g(x)) to Failure with diff(f(x),x).subs(f(x) == g(x))

### comment:16 in reply to: ↑ 11 Changed 4 years ago by rws

The above consists of three problems. The central one is the failure to `f(x).subs(f(x) == g(x))`; the `diff` case is probably only a result; it looks like this is a Pynac bug, and when fixed there it should be doctested here.

The special status of `fderivative` in Pynac (not a function) may be the reason, see also https://groups.google.com/d/msg/sage-support/lZ4AjbmvvQE/-BJ_xvMlAQAJ

### comment:17 Changed 4 years ago by jdemeyer

• Milestone changed from sage-7.7 to sage-8.0

Milestone renamed