Opened 10 years ago

Last modified 2 years ago

#6480 new defect

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

Reported by: gmhossain Owned by:
Priority: major Milestone: sage-8.0
Component: symbolics Keywords:
Cc: kcrisman, mjo, eviatarbach, jakobkroeker Merged in:
Authors: Reviewers:
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps: wrongAnswerMarker

Description (last modified by rws)

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[0](f)(x)
sage: g.subs_expr(f(x)==f(x)+df(x))
D[0](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[0](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[0](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[0](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[0](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[0](g)(1).

Change History (18)

comment:1 Changed 8 years ago by kcrisman

  • Cc kcrisman added
  • Report Upstream set to N/A

comment:2 Changed 7 years ago by mjo

  • Cc mjo added

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

comment:3 Changed 6 years ago by eviatarbach

  • Cc eviatarbach added

comment:5 Changed 6 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 6 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 4 years ago by jakobkroeker

  • Stopgaps set to todo

comment:8 Changed 2 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[0](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[0](g)(1)

I opened #22401 for this.

comment:9 Changed 2 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[0](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 2 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[67]>", 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[68]>", 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[71]>", 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[73]>", line 1, in <module>
        df.subs(f == f + g)
    TypeError: unsupported operand type(s) for +: 'NewSymbolicFunction' and 'NewSymbolicFunction'

comment:11 follow-up: Changed 2 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 2 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 2 years ago by rws

  • Description modified (diff)

comment:14 Changed 2 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 2 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 2 years ago by rws

Replying to 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 2 years ago by jdemeyer

  • Milestone changed from sage-7.7 to sage-8.0

Milestone renamed

comment:18 Changed 2 years ago by jakobkroeker

  • Cc jakobkroeker added
  • Stopgaps set to wrongAnswerMarker
Note: See TracTickets for help on using tickets.