Temat: Zmiana zmiennych w wyrażeniu zawierającym pochodne cząstkowe

Podniże znajduje się zbiór funkcji pozwalający na zamianę zmiennych w prostych (niefunkcyjnych) wyrażeniach zawierających pochodne cząstkowe dowolnego rzędu i w dowolnym wymiarze. Jest to wersja pozbawiona kontroli błędów, więc proszę używać na własne ryzyko. Funkcja nie wymaga podawania funkcji odwrotnej do funkcji definiującej zamianę zmiennych. Sposób użycia to np:

spherical = {# Cos[#3] Sin[#2] &, # Sin[#3] Sin[#2] &, # Cos[#2] &};
rules=ChangeVariable[f, {x, y, z}, spherical, {r, th, ph}, g];
f[x, y, z] + D[f[x, y, z], x, x] + D[f[x, y, z], y, y] + 
    D[f[x, y, z], z, z] /.rules // Simplify

"f" to nagłówek funkcji zastępowanej, {x,y,z} to nazwy dotychczasowych zmiennych, w miejscu "spherical" należy wstawić listę funkcji definiujących stare współrzędne ({x(r,th,ph),y(r,th,ph),...}), dalej nazwy nowych współrzędnych (np. {r,th,phi}) a na końcu nagłówek funkcji nowych zmiennych (może to być właściwie dowolny niezdefiniowany symbol).

Clear[Grad, Jac, InvJacGrad, ChangeVariable];
Grad[f_, args_] := Module[{IdM},
  IdM = IdentityMatrix[Length[args]];
  Evaluate[Derivative[Sequence @@ #][f]] @@ args & /@ IdM
  ]
Jac[yOf_, args_] := Module[{IdM},
  IdM = IdentityMatrix[Length[args]];
  Transpose[
   Outer[Derivative[Sequence @@ #][#2] @@ args &, IdM, yOf, 1]]
  ]
InvJacGrad[f_, x_, args_, l_] := Module[{ytemp},
  If[Length[l] == 0, f,
   ytemp = Unique[args];
   Function[
    Evaluate[ytemp],
    Evaluate[(
       Transpose[Inverse[Jac[x, ytemp]]].Grad[
         InvJacGrad[f, x, ytemp, Rest[l]],
         ytemp](*Inverse Jacobian used!*)
       )[[First[l]]]
     ]]
   ]
  ]
ChangeVariable[f_, args_, xOf_, newArgs_, g_] := Module[{},
  {
   Derivative[l__][f] @@ args :> Module[{k = List[l]},
     InvJacGrad[g, xOf, newArgs,
       Flatten[ConstantArray[#, k[[#]]] &
         /@ Range[Length[k]]]] @@ newArgs
     ],
   f @@ args -> g @@ newArgs,
   Sequence @@ Thread[args -> Through[xOf @@ newArgs]]
   }
  ]

Ostatnio edytowany przez pawel.biernat (2009-10-14 09:20:28)

2

Odp: Zmiana zmiennych w wyrażeniu zawierającym pochodne cząstkowe

Sprawdziłem transformacje laplacianu w 3 wymiarach do wsp. sferycznych i jest OK.
Ale:

bieg = {#1 Cos[#2] &, #1  Sin[#2] &};
rules = ChangeVariable[f, {x, y}, bieg, {r, th}, g];
D[f[x], x] /. rules // Simplify

daje:

f'[r Cos[th] ]
Mathematica 7.0.1, Windows 7 64bit, 6 GB RAM

3

Odp: Zmiana zmiennych w wyrażeniu zawierającym pochodne cząstkowe

Jest to prosta wersja skryptu, i jako taka wymaga podania funkcji wszystkich argumentów tj. "D[f[x,y],x]". Po takiej modyfikacji zamiana zmiennych działa prawidłowo.

bieg = {#1 Cos[#2] &, #1  Sin[#2] &};
rules = ChangeVariable[f, {x, y}, bieg, {r, th}, g];
D[f[x,y], x] /. rules // Simplify

Wynikiem jest wtedy

-((Sin[th]*Derivative[0, 1][g][r, th])/r) + 
 Cos[th]*Derivative[1, 0][g][r, th]

Z pewnością wystarczy drobna modyfikacja by program działał dla funkcji także o dowolnych argumentach (np z parametrem), pomyślę jeszcze o tej poprawce.

Z drugiej strony, co jeśli użytkownik poda argumenty w sposób niespójny? np najpierw f[x,y,t] a w innym miejscu f[t,x,y]? Program może wykryć położenia argumentów i inteligentnie pozamieniać zmienne, ale co jeśli użytkownik niedoczyta dokumentacji a ma na myśli równanie funkcyjne (np f[x,y] w jednym miejscu a f[y,x] w drugim)? Skrypt bez zająknięcia poda wynik (fałszywy), z którego nieświadomy użytkownik będzie korzystał. Chyba lepiej trzymać się jednej konwencji i pisać wszystkie argumenty i na właściwych miejscach, a podany przez Pana przypadek dodać do kontroli błędów.

Ostatnio edytowany przez pawel.biernat (2009-10-15 10:28:09)

4

Odp: Zmiana zmiennych w wyrażeniu zawierającym pochodne cząstkowe

Mój drugi przykład powyżej był nonsensowny. Zamiana dotyczy tylko zmiennych niezależnych. Dla jednej zmiennej procedura tez działa dobrze, np:

rule = ChangeVariable[y, {x}, {\[Phi][#] &}, {t}, Y]
y''[x] /. rule // Expand

i daje poprawny wynik.


Analiza tej procedury przyprawia jednak o ból głowy. W pierwszej chwili fakt, że podstawia ona za pochodne dowolnego rzędu wygląda na bardzo tajemniczy, szczególnie że nie są nigdzie używane
f. odwrotne ani żadne gotowe wzory. Gdyby jednak minimalnie uporządkować kod:

InvJacGrad[f_, x_, args_, l_] := Module[{ytemp},
  
  If[Length[l] == 0, f, ytemp = Unique[args];
   Function[Evaluate[ytemp],
    Evaluate[
     (
       Transpose[Inverse[Jac[x, ytemp]]].Grad[
         InvJacGrad[f, x, ytemp, Rest[l]], 
         ytemp](*Inverse Jacobian used!*)
       )
      [[ First[l] ]]
     ](* end of Evaluate *)
    ](* end of Function*)
   ](* end of If *)
  
  ]

to można wreszcie zauważyć, że f. InvJacGrad wywołuje się rekursywnie zdejmując po kolei
elementy z listy l (Rest[l]). Lista l, o ile dobrze zrozumialem, służy wyłącznie jako rodzaj iteratora.

Mathematica 7.0.1, Windows 7 64bit, 6 GB RAM