On Thu, 19 Nov 2020 at 01:23, Aaron Meurer <[email protected]> wrote:
>
> On Wed, Nov 18, 2020 at 5:37 PM Oscar <[email protected]> wrote:
> >
> > Hi David,
> >
> > It's not completely intuitive but you can do the substitution in several 
> > stages. In your example (this is run isympy where f and g are both 
> > functions):
> >
> > In [24]: eq = Eq(n**2*f(x) - x*Derivative(f(x), x) + (1 - 
> > 2*x)*Derivative(f(x), (x, 2)), 0)
> >
> > In [25]: eq
> > Out[25]:
> >                                    2
> >  2          d                     d
> > n ⋅f(x) - x⋅──(f(x)) + (1 - 2⋅x)⋅───(f(x)) = 0
> >             dx                     2
> >                                  dx
> >
> > In [26]: eq.subs(f(x), g(cos(t)))
> > Out[26]:
> >                                              2
> >  2               d                          d
> > n ⋅g(cos(t)) - x⋅──(g(cos(t))) + (1 - 2⋅x)⋅───(g(cos(t))) = 0
> >                  dx                          2
> >                                            dx
> >
> > In [27]: eq.subs(f(x), g(cos(t))).doit()
> > Out[27]:
> >  2
> > n ⋅g(cos(t)) = 0
>
> Isn't this wrong? You are replacing f(x) with an expression that does
> not depend on x, then evaluating the derivatives that are still in
> terms of x, so they go to 0.

I obviously wasn't paying enough attention when I wrote that :)

Yes, I remember. This kind of substitution of the independent variable
is more difficult. Here's a different example that works (a
Cauchy-Euler ODE):

In [231]: eq = x**2 * f(x).diff(x, 2) + x * f(x).diff(x) + f(x)

In [232]: eq
Out[232]:
     2
 2  d            d
x ⋅───(f(x)) + x⋅──(f(x)) + f(x)
     2           dx
   dx

In [233]: xf = Function('x') # make x a function of t

In [234]: xs = exp(t) # substitution

In [235]: eqf = eq.subs(x, xf(t))

In [236]: eqf
Out[236]:
                   2
           2      d                      d
f(x(t)) + x (t)⋅──────(f(x(t))) + x(t)⋅─────(f(x(t)))
                     2                 dx(t)
                dx(t)

In [237]: diffx = lambda e, n: diffx(diffx(e, n-1), 1) if n>1 else
Derivative(e, t) / Derivative(xf(t), t)

In [238]: changex = lambda e: e.replace(Derivative, lambda e, vs:
diffx(e, vs[1]))

In [239]: changex(eqf)
Out[239]:
                  ⎛d          ⎞
                  ⎜──(f(x(t)))⎟
           2    d ⎜dt         ⎟
          x (t)⋅──⎜───────────⎟
                dt⎜  d        ⎟        d
                  ⎜  ──(x(t)) ⎟   x(t)⋅──(f(x(t)))
                  ⎝  dt       ⎠        dt
f(x(t)) + ───────────────────── + ────────────────
                 d                    d
                 ──(x(t))             ──(x(t))
                 dt                   dt

In [240]: changex(eqf).doit()
Out[240]:
                   2
           2      d                      d
f(x(t)) + x (t)⋅──────(f(x(t))) + x(t)⋅─────(f(x(t)))
                     2                 dx(t)
                dx(t)

In [241]: changex(eqf).doit() == eqf
Out[241]: True

In [242]: changex(eqf).subs(f(xf(t)), g(t)).subs(xf(t),
xs).doit().expand()
Out[242]:
         2
        d
g(t) + ───(g(t))
         2
       dt


Applying the same technique to the equation you showed doesn't lead to
a simple result though:

In [243]: eq = n**2*f(x) - x*Derivative(f(x), x) + (1 -
2*x)*Derivative(f(x), (x, 2))

In [244]: xs = cos(t)

In [245]: eqf = eq.subs(x, xf(t))

In [246]: changex(eqf).doit() == eqf
Out[246]: True

In [247]: changex(eqf).subs(f(xf(t)), g(t)).subs(xf(t),
xs).doit().expand()
Out[247]:
                                       2           2
                                      d           d
                 d          2⋅cos(t)⋅───(g(t))   ───(g(t))        2
d                 d
          cos(t)⋅──(g(t))              2           2         2⋅cos
(t)⋅──(g(t))   cos(t)⋅──(g(t))
 2               dt                  dt          dt
dt                dt
n ⋅g(t) + ─────────────── - ────────────────── + ───────── +
────────────────── - ───────────────
               sin(t)               2                2               3
                  3
                                 sin (t)          sin (t)         sin
(t)             sin (t)

In [248]: _.collect(g(t))
Out[248]:
                                   2         ⎛              2
   ⎞
 2        ⎛  2⋅cos(t)      1   ⎞  d          ⎜cos(t)   2⋅cos (t)
cos(t)⎟ d
n ⋅g(t) + ⎜- ──────── + ───────⎟⋅───(g(t)) + ⎜────── + ───────── -
───────⎟⋅──(g(t))
          ⎜     2          2   ⎟   2         ⎜sin(t)       3
3   ⎟ dt
          ⎝  sin (t)    sin (t)⎠ dt          ⎝          sin (t)    sin (t)⎠


> > Ideally sympy would have a function like maple's dchange:
> > https://www.maplesoft.com/support/help/Maple/view.aspx?path=PDEtools/dchange
> > https://github.com/sympy/sympy/issues/17590
>
> I wonder if we need a separate function or if subs() itself should
> just do this.

I think that subs could do some parts of this but a function for
change of variables in derivatives would still be useful. It's tricky
to keep track of transformations in both directions so I would expect
a dsubs function to return something to help with that as well as the
transformed equation. There are also several different forms of
substitution for ODEs and a dsubs function could handle them all.

Oscar

-- 
You received this message because you are subscribed to the Google Groups 
"sympy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sympy/CAHVvXxT3KZY4ZZSE8LdNHdHgn28CsH8KGPcuMneFWJxiNuSzGA%40mail.gmail.com.

Reply via email to