FW: Symbolic computation with vector fields and tensors

*To*: mathgroup at smc.vnet.net*Subject*: [mg46803] FW: [mg46767] Symbolic computation with vector fields and tensors*From*: "Wolf, Hartmut" <Hartmut.Wolf at t-systems.com>*Date*: Tue, 9 Mar 2004 04:30:46 -0500 (EST)*Sender*: owner-wri-mathgroup at wolfram.com

An amendment to my reply, see below -----Original Message----- From: Wolf, Hartmut To: mathgroup at smc.vnet.net Subject: [mg46803] RE: [mg46767] Symbolic computation with vector fields and tensors >-----Original Message----- >From: J Krugman [mailto:jkrugman345 at yahbitoo.com] To: mathgroup at smc.vnet.net >Sent: Sunday, March 07, 2004 7:34 AM >To: mathgroup at smc.vnet.net >Subject: [mg46803] [mg46767] Symbolic computation with vector fields and tensors > > > >I'm trying to set up a symbolic computation involving covariant and >contravariant vector fields, and second-order covariant tensors. >Mathematica is probably the best tool for this, but I'm having a hard >time getting past square one. > >My first problem is in getting Mathematica to recognize the standard >algebra of functions, whereby "f + g" denotes the function whose value >at x is f[x] + g[x], etc. For example: > > In[1]= > f[x_] := x+1; > g[x_] := 3x; > h = f + g; > h[x] > > Out[4]= > (f+g)[x] > >I know that I can always define h "pointwise" with the statement >h[x_]:=f[x]+g[x], instead of the "functional" approach I use above, >but I want to avoid this if possible. I'm also aware of Through, but >I want Mathematica to perform these conversions automatically (e.g. in >respond to Expand) without prompting from me. > >A trickier problem is illustrated by the following. L and M are two >differential operators, and the map LD returns the differential >operator obtained from the commutator (in the sense of composition) of >its two arguments: > >In[5]:= >L[f_] := A[1] Derivative[1, 0][f] + A[2] Derivative[0, 1][f]; >M[f_] := B[1] Derivative[1, 0][f] + B[2] Derivative[0, 1][f]; >LD[L_, M_][f_] := Composition[L, M][f] - Composition[M, L][f]; >LD[L, M][f]//Expand//OutputForm > > In[5]:= > L[f_] := A[1] Derivative[1, 0][f] + A[2] Derivative[0, 1][f]; > M[f_] := B[1] Derivative[1, 0][f] + B[2] Derivative[0, 1][f]; > LD[L_, M_][f_] := Composition[L, M][f] - Composition[M, L][f]; > LD[L, M][f]//Expand//OutputForm > > Out[8]//OutputForm= > (0,1) (1,0) (0,1) > -(B[2] (A[2] f + A[1] f ) ) + > > (0,1) (1,0) (0,1) > A[2] (B[2] f + B[1] f ) - > > (0,1) (1,0) (1,0) > B[1] (A[2] f + A[1] f ) + > > (0,1) (1,0) (1,0) > A[1] (B[2] f + B[1] f ) > > >How can I get Mathematica to compute, for example, the first partial >derivative of > > (0,1) (1,0) > (A[2] f + A[1] f ) > >and do so automatically (e.g. in response to Expand). In fact, >how can I get Mathematica to acknowledge the linearity of the >derivative and Leibniz's rule? > > In[12]:= > Expand[Derivative[1,0][a b + c d]]//OutputForm > > Out[12]//OutputForm= > (1,0) > (a b + c d) > >(Incidentally, I need Derivative, and not D, because I want to be >able to specify partial derivatives in terms of sets of >subscripts/superscripts.) > > >I wish I had better technical documentation for Mathematica. The >Mathematica Book is basically a large collection of examples, which, >however clever or illuminating, is no substitute for formal APIs. >The number of important details that the Mathematica Book, despite >its heft, leaves unsaid is vast. As a result, I end up figuring >out these details by sheer trial and error. (I know that Mr. >Wolfram is very enthusiastic about "computer experimentation", but >I trust that he is not trying to promote it by making the Mathematica's >documentation cryptic.) In some cases, like those that lead to >this post, my trial and error gets me nowhere. Is there anything >better as far as technical reference material for Mathematica goes? > >Thanks! > >jill > >P.S. To send me mail, splice out the string bit from my address. > Jill, let's see first, what we can do with the existing documentation! If you look at Help for Derivative you'll read: ... [] Derivative is generated when you apply D to functions whose derivatives Mathematica does not know. [] Mathematica attempts to convert Derivative[n][f] and so on to pure functions. Whenever Derivative[n][f] is generated, Mathematica rewrites it as D[f[#]&, {#, n}]. If Mathematica finds an explicit value for this derivative, it returns this value. Otherwise, it returns the original Derivative form. ... Look also at the examples there. ... You have to tell Derivative what to do! More exactly, Derivative doesn't do anything, it just indicates expressions to be differentiated, the working horse is D. Just an idea, you might try something like In[41]:= slotOn[expr_, slotd_] := With[{slots = Sequence @@ (Slot /@ Range[slotd])}, Function[Evaluate[Replace[expr, s_Symbol :> s[slots], {-1}]]]] In[44]:= slotOff[expr_] := expr /. Function[body_] :> (body /. x_[Slot[_] ..] :> x) In[45]:= Derivative[1, 0][slotOn[a b + c d, 2]] // slotOff Out[45]//OutputForm= (1,0) (1,0) (1,0) (1,0) b a + a b + d c + c d I can't help you with your attempt In[5] etc. since you didn't tell (me nor Mathematica), what A[1] etc. are (also considered as functions? or constants?). If you try to follow this idea, of course, you have to refine that function slotOn; i.e. tell more precisely which symbols are to be considered as functions (and perhaps, where they do appear in the expressions). The most simple, or better, way however, would be to follow help, and mark your functions as such from the very beginning, e.g. In[24]:= f = (# + 1 &); g = (3# &); h = Thread[f + g, Function] Out[26]= (#1 + 1) + 3 #1 & You may try to go ahead with this for your L, M, LD (and threading Function where necessary -- it might be a bit tricky!). If I do, assuming A[1], A[2], etc. were constants, I get In[49]:= LD[L, M][f[#1, #2] &] // OutputForm Out[49]//OutputForm= (0,1) (0,1) (1,0) (0,1) -(B[2] (A[2] (f ) [#1, #2] + A[1] (f ) [#1, #2]) + (0,1) (1,0) B[1] (A[2] (f ) [#1, #2] + (1,0) (1,0) A[1] (f ) [#1, #2])) + (0,1) (0,1) (A[2] (B[2] (f ) [#1, #2] + (1,0) (0,1) B[1] (f ) [#1, #2]) + (0,1) (1,0) (1,0) (1,0) A[1] (B[2] (f ) [#1, #2] + B[1] (f ) [#1, #2]) ) & As Function has the HoldAll Attribute you can't just expand this, you have to expand the body of the function, e.g. like this In[50]:= LD[L, M][f[#1, #2] &] /. Function[body_] :> With[{expdb = Expand[body]}, expdb & /; True] Out[50]= 0 & The result is the identical zero function (as you might compute by hand). As with this observation... In[53]:= Derivative[1, 1][f[#1, #2] &] // OutputForm Out[53]//OutputForm= (1,0) (0,1) (f ) [#1, #2] & we see how Mathematica tries to differentiate; if you don't like the result, you might have to add your rules to bring that back to In[56]:= Derivative[1, 1][f][#1, #2] & // OutputForm Out[56]//OutputForm= (1,1) f [#1, #2] & and other similar forms. Another remark might be in place: Obviously you try doing something that has been done serveral times before. Perhaps you should take a glimpse into those available packages, and only then try something special, as you prefer it. And writing such a package isn't quite easy. Good luck! --------------- Amendment: Perhaps I should have been more specific, and use the less trivial interpretation for A, B: In[1]:= L[f_Function] := Thread[Thread[(A[1][#1, #2] &) Derivative[1, 0][f], Function] + Thread[(A[2][#1, #2] &) Derivative[0, 1][f], Function], Function] In[2]:= L[f[#1, #2] &] // OutputForm Out[2]//OutputForm= (0,1) (1,0) A[2][#1, #2] f [#1, #2] + A[1][#1, #2] f [#1, #2] & In[3]:= M[f_Function] := Thread[Thread[(B[1][#1, #2] &) Derivative[1, 0][f], Function] + Thread[(B[2][#1, #2] &) Derivative[0, 1][f], Function], Function] In[6]:= LD[L_, M_][f_] := Thread[Composition[L, M][f] + Thread[-Composition[M, L][f], Function], Function] To understand the need for the inner Thread, consider FullForm. In[13]:= LD[L, M][f[#1, #2] &] /. Function[body_] :> With[{newb = Expand[body]}, newb & /; True] // OutputForm Out[13]//OutputForm= (0,1) (0,1) -(B[2][#1, #2] f [#1, #2] (A[2]) [#1, #2]) + (0,1) (0,1) A[2][#1, #2] f [#1, #2] (B[2]) [#1, #2] - (0,1) (1,0) B[2][#1, #2] (A[1]) [#1, #2] f [#1, #2] + (0,1) (1,0) A[2][#1, #2] (B[1]) [#1, #2] f [#1, #2] - (1,0) (1,0) B[1][#1, #2] f [#1, #2] (A[1]) [#1, #2] - (0,1) (1,0) B[1][#1, #2] f [#1, #2] (A[2]) [#1, #2] + (1,0) (1,0) A[1][#1, #2] f [#1, #2] (B[1]) [#1, #2] + (0,1) (1,0) A[1][#1, #2] f [#1, #2] (B[2]) [#1, #2] & Now, if you like In[15]:= % // slotOff // OutputForm Out[15]//OutputForm= (0,1) (0,1) (0,1) (0,1) -(B[2] f (A[2]) ) + A[2] f (B[2]) - (0,1) (1,0) (0,1) (1,0) B[2] (A[1]) f + A[2] (B[1]) f - (1,0) (1,0) (0,1) (1,0) B[1] f (A[1]) - B[1] f (A[2]) + (1,0) (1,0) (0,1) (1,0) A[1] f (B[1]) + A[1] f (B[2]) -- Hartmut Wolf