New Personal Introduction

93 views
Skip to first unread message

אוריאל מליחי

unread,
Nov 15, 2020, 9:59:38 PM11/15/20
to sympy
hello everyone!
my name is Oriel Malihi and I'm in my last year of Computer Science and Mathematics degree in Ariel University (israel). I'm new to Python and its librarys but I'm ready to learn .and contribute as much as I can. Looking forward to to be working with you all
if it helps I have some experiance in c, c++, and java programing.

David Bailey

unread,
Nov 18, 2020, 7:08:01 PM11/18/20
to sy...@googlegroups.com

Dear Group,

Suppose I have a differential equation such as:

Eq(n^2*f(x) - x*Derivative(f(x), x) + (1 - 2*x)*Derivative(f(x), (x, 2)))

(Though typically more complicated)

and I want to replace the x variable - say x=cos(t)

Is there a way to make that substitution within SymPy and get back a differential equation in t, as opposed to simply throwing the equation to dsolve and hoping that it will solve it?

Likewise, is it possible to make a change of variable within an integral without simply letting integrate loose on it?

David



Oscar

unread,
Nov 18, 2020, 7:37:45 PM11/18/20
to sympy
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

More substitutions are probably needed to continue from here.

Ideally sympy would have a function like maple's dchange:

Oscar

Aaron Meurer

unread,
Nov 18, 2020, 8:08:56 PM11/18/20
to sympy
> Likewise, is it possible to make a change of variable within an integral without simply letting integrate loose on it?

Integral.transform should do what you're looking for here.

Aaron Meurer

Aaron Meurer

unread,
Nov 18, 2020, 8:23:19 PM11/18/20
to sympy
On Wed, Nov 18, 2020 at 5:37 PM Oscar <oscar.j....@gmail.com> 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.

>
> More substitutions are probably needed to continue from here.
>
> 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. OTOH that might break existing code, since currently
subs works like

>>> diff(f(x), x).subs(f(x), y)
Derivative(y, x)

which is intended behavior since it allows using subs iteratively to
do changes of variables, or things like cse().

Aaron Meurer

>
> Oscar
> On Thursday, 19 November 2020 at 00:08:01 UTC da...@dbailey.co.uk wrote:
>>
>> Dear Group,
>>
>> Suppose I have a differential equation such as:
>>
>> Eq(n^2*f(x) - x*Derivative(f(x), x) + (1 - 2*x)*Derivative(f(x), (x, 2)))
>>
>> (Though typically more complicated)
>>
>> and I want to replace the x variable - say x=cos(t)
>>
>> Is there a way to make that substitution within SymPy and get back a differential equation in t, as opposed to simply throwing the equation to dsolve and hoping that it will solve it?
>>
>> Likewise, is it possible to make a change of variable within an integral without simply letting integrate loose on it?
>>
>> David
>>
>>
>>
> --
> 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 sympy+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/07b2ec37-30b8-4a6f-8690-c05bfe958ce0n%40googlegroups.com.

Oscar Benjamin

unread,
Nov 19, 2020, 10:37:29 AM11/19/20
to sympy
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

David Bailey

unread,
Nov 25, 2020, 11:37:28 AM11/25/20
to sy...@googlegroups.com
On 19/11/2020 15:37, Oscar Benjamin wrote:

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

I know the feeling, because I also managed to garble the differential equation, which should read:

n**2*f(x) - x*Derivative(f(x), x) + (1 - x**2)*Derivative(f(x), (x, 2))

I am pretty sure that should resolve to a simple differential equation after the substitution x=cos(t)

I tried to follow your prescription but I think the confusion may have set in here,

In [233]: xf = Function('x') # make x a function of t
because I guess I don't need xf because the ODE is already represented in terms of an undefined function f(x).

I also had difficulty following what you were doing once I  reached the nested lambda expressions!

It would be great if you could find the time to demonstrate your method on my example - a working example is always worth its weight in gold.

When I originally put in this query, I had assumed that there would be a one-line answer buried in SymPy.

I have also explored my own Python solution to the problem, recursively processing down the whole ODE expression and picking off the derivatives as I come across them. It looks feasible, but it isn't finished yet.

I know it is a very busy time for you right now, so if you want to put this in your pending tray for a week, that is fine :)

David


Oscar Benjamin

unread,
Nov 25, 2020, 12:42:27 PM11/25/20
to sympy
On Wed, 25 Nov 2020 at 16:37, David Bailey <da...@dbailey.co.uk> wrote:
>
> On 19/11/2020 15:37, Oscar Benjamin wrote:
>
>
> I obviously wasn't paying enough attention when I wrote that :)
>
> I know the feeling, because I also managed to garble the differential equation, which should read:
>
> n**2*f(x) - x*Derivative(f(x), x) + (1 - x**2)*Derivative(f(x), (x, 2))
>
> I am pretty sure that should resolve to a simple differential equation after the substitution x=cos(t)

Okay now it works:

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

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

In [24]: xs = cos(t)

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

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

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

In [28]: assert changex(eqf).doit() == eqf

In [29]: eqsubs = changex(eqf).subs(f(xf(t)), g(t)).subs(xf(t),
xs).doit()

In [30]: str(trigsimp(eqsubs))
Out[30]: 'n**2*g(t) + Derivative(g(t), (t, 2))'

> I tried to follow your prescription but I think the confusion may have set in here,
>
> In [233]: xf = Function('x') # make x a function of t
>
> because I guess I don't need xf because the ODE is already represented in terms of an undefined function f(x).

Yes but we need x to become x(t) because otherwise x.diff(t) will just
be zero. Maybe that is unnecessary though if we skip through to an
equation in a new function g anyway... Maybe I just did this so the
sanity check (changex(eqf).doit() == eqf) works but that step isn't
strictly needed.

> I also had difficulty following what you were doing once I reached the nested lambda expressions!
>
> It would be great if you could find the time to demonstrate your method on my example - a working example is always worth its weight in gold.
>
> When I originally put in this query, I had assumed that there would be a one-line answer buried in SymPy.

We definitely do need to supply a function for doing this. It's really
not trivial to get this right. If we had something like dsubs or
dchange then we could make use of it internally as well (e.g. in the
ode module).

--
Oscar

David Bailey

unread,
Nov 25, 2020, 2:59:43 PM11/25/20
to sy...@googlegroups.com
On 25/11/2020 17:42, Oscar Benjamin wrote:
On Wed, 25 Nov 2020 at 16:37, David Bailey <da...@dbailey.co.uk> wrote:

      
Okay now it works:
I really appreciate that!



We definitely do need to supply a function for doing this. It's really
not trivial to get this right. If we had something like dsubs or
dchange then we could make use of it internally as well (e.g. in the
ode module).

That is what I had expected would be there - just as you already have for integration in Integral.transform - which is presumably more difficult because you also have the limits to take care of.

Best wishes,

David

Reply all
Reply to author
Forward
0 new messages