Re: Derivatives D[ ] as Functions: Summary (LONGISH)
- To: mathgroup at smc.vnet.net
- Subject: [mg13362] Re: Derivatives D[ ] as Functions: Summary (LONGISH)
- From: "Allan Hayes" <hay at haystack.demon.cc.uk>
- Date: Mon, 20 Jul 1998 02:50:15 -0400
- References: <6nsil0$f32@smc.vnet.net> <6okijd$1ft@smc.vnet.net>
- Sender: owner-wri-mathgroup at wolfram.com
I have intepolated comments in the following message, including, for completeness, some from my previous related posting. Unfortunately this raises it the posting from Longish to Long. However the issues raised seem important. ------------------------------------------------------------- Allan Hayes Training and Consulting Leicester UK http://www.haystack.demon.co.uk hay at haystack.demon.co.uk voice: +44 (0)116 271 4198 fax: +44(0)116 271 8642 ---------------------------------------------------------------------------- - AES wrote in message <6okijd$1ft at smc.vnet.net>... >I recently posed the question of defining a function f2 as the >derivative of another function f1, e.g. > > Remove["Global`*"]; > > f1[a_,x_] :=a Cos[x] + a^2 Sin[x]; > f2[a_,x_] := D[f1[a,x],x]; > >and then finding that f2 would not behave "as expected" in a subsequent >Plot[ ] or Table[ ]. > >Thanks to several people for their responses, and apologies for my >several typos in earlier postings. It's clear what my difficulty was. Clear["Global`*"] f1[a_,x_] :=a Cos[x] + a^2 Sin[x]; f2[a_,x_] := D[f1[a,x],x]; For Table we get Table[f2[a,x],{x,1,2}] General::ivar: 1 is not a valid variable. General::ivar: 2 is not a valid variable. 2 2 {D[a Cos[1] + a Sin[1], 1], D[a Cos[2] + a Sin[2], 2]} This is because Table does not evaluate f2[x,y] itself (it hs the Attribute HoldAll); but for each numerical values of x supplied by the iterator {x,0,1}, say x =1 it finds the corresponding table entry by a process like x=1; f2[a,x] General::ivar: 1 is not a valid variable. 2 D[a Cos[1] + a Sin[1], 1] and differentiating with respect to the number 1 makes no sense. To avoid this we need to evaluate f2[a,x] before x is assigned the value 1 With the example given, the pre-evaluation can be achieved in several ways (method (2) below is probably the most common way) Ill modify the example to show {x,f1[a,x], f2[a,x]} a=2; (1) Table[Block[{x},{x, f1[a,x], f2[a,x]}]//N , {x,1,2}] // TableForm 1. 4.44649 0.478267 2. 2.8049 -3.48318 (2) x=. (* essential for this method*) Table[Evaluate[{x, f1[a,x], f2[a,x]}] , {x,1,2}]//N // TableForm 1. 4.44649 0.478267 2. 2.8049 -3.48318 (3) Make the definitions of f1 and f2 immediate, so that the differentiation is done before we construct the Table expression - this is the most efficient way. Clear["Global`*"] f1[a_,x_] =a Cos[x] + a^2 Sin[x]; f2[a_,x_] = D[f1[a,x],x]; a=2; Table[{x, f1[a,x], f2[a,x]} // N, {x,1,2}] // TableForm 1. 4.44649 0.478267 2. 2.8049 -3.48318 > > >However, let's look at the general issue a little further. If for >example we do the above and then look at the FullForm version of the >two functions, they look very similar: > > f1[a,x]//FullForm > > Plus[Times[a,Cos[x]],Times[Power[a,2],Sin[x]]] > > f2[a,x] // FullForm > > Plus[Times[Power[a,2],Cos[x]],Times[-1,a,Sin[x]]] > >Note that these FullForm results, if not misleading, certainly give no >clue that f2 has a different character than f1 and will behave totally >differently if you try to use it in Plot[ ] or Table[ ] . > A general and frequent and serious problem with Mathematica, in fact, >is that it often does things that may be totally logical and even >necessary by its rules, but that can be mysterious, non-intuitive, and >frustrating to ordinary users; and the nature of the beast often makes >these problems obscure and hard to find. Clear["`*"] f1[a_,x_] :=a Cos[x] + a^2 Sin[x]; f2[a_,x_] := D[f1[a,x],x]; f2[a,x] // FullForm first evaluates f2[a,x] and then shows the full form of the result. This seems to me to be straight forward. To see the stored expression we can use. ?f2 Global`f2 f2[a_, x_] := D[f1[a, x], x] And to see all the stored definitions that would be used in a current evaluation we can use FullDefinition[f2] f2[a_, x_] := D[f1[a, x], x] 2 f1[a_, x_] := a Cos[x] + a Sin[x] > >[As another example of Mathematica's penchant for obscure difficulties, >note that if you follow the usual practice that you are allowed to use >for (all? most?) other compound expressions and include the "Remove[ >]" expression in the same cell as the two function definitions above, >the two definitions will be Removed, even though they come AFTER the >Remove[ ]. Tell me why this makes sense? -- not what combination of >rules makes Remove[ ] function this way, but why setting it up in this >way makes sense? Also, tell me where you're warned about this in the >Mathematica Book?] This is tricky, here is my attempt at an explanation Take an example: Remove[a];a=5;a^2 25 ?a Information::notfound: Symbol a not found. The explanation seems to be that on evaluating the compound expression, Remove[a] causes a to be replaced by Removed[a] for the rest of the evaluation. So, we get the assignment Removed[a] = 5; then evaluate Removed[a]^2 to get the output 25. But then all occurences and definitions involving Removed[a] and a are removed. This explanation is supported by the following TracePrint. In[57]:= (Remove[a];a=5;a^2)//TracePrint 2 Remove[a]; a = 5; a CompoundExpression Remove[a] Remove Null Removed[a] = 5 Set 5 5 2 Removed[a] Power Removed[a] 5 2 2 5 25 25 Out[57]= 25 > >[Another general observation is that when problems -- or anyway >"apparent problems" -- with Mathematica's ways of doing things are >pointed out, I find it's much more common to get a detailed explanation >of why Mathematica does what it does, rather than any discussion of the >design choices, or design necessities, that make it necessary -- if it >is necessary -- for Mathematica to function in this way.] A single source for fuller information on design choices would be welcome. > >In any event one way to avoid the derivative problem above is to use an >immediate definition, i.e., use " = " instead of " := "in defining f2: > > f1[a_,x_] :=a Cos[x] + a^2 Sin[x]; > f2[a_,x_] = D[f1[a,x],x]; > >That's fine -- except, suppose you do this deep in a notebook in which >"a" has already been given a value; you may not get what you want, or >think you're getting.. I know of no general solution to this problem. Using Block can temporarily protect a from outside definitions (Module would change a to a$n for some positive integer n , which might not be appropriate). More about this later. > >Several people also suggested using Evaluate[f2[a,x]], or more complex >tricks, every time you use f2 subsequently in a Plot[ ] or Table[ ], >and that of course works. > >However, so far as I can see the preferred way to accomplish this >would seem to be to do it globally, i.e., to write: > > f1[a_,x_] := a Cos[x] + a^2 Sin[x]; > f2[a_,x_] := Evaluate[ D[f1[a,x],x]]; > >That's reasonably easy to remember, somewhat intuitive (to me anyway), >seems to meet the need, and what I propose to do from now on. But, are >there still hidden pitfalls in this? Further comments welcome. What is the advantage of using f2[a_,x_] := Evaluate[ D[f1[a,x],x]];? It looks like lhs:=Evaluate[rhs ]; is equivalent to lhs=rhs; except for two features: (1) where an explicit = is needed: For example we have xx = {1,3}; xx[[2]]=5 ;xx {1, 5} but yy := Evaluate[{1,3}]; yy[[2]]=5;yy Set::noval: Symbol yy in part assignment does not have an immediate value. {1, 3} (2) Output: The output from yy := Evaluate[{1,3}] is Null, whereas that from xx = {1,3} is {1,3} And, to return to the problem of protecting of variables from outside definitions, f2[a_,x_] :=Evaluate[ D[f1[a,x],x]]; will not avoid picking up existing definitions of a (or of x) However as mentioned earlier this sort of thing might be tackled with Block a= 2;x=3;Block[{a,x},f2[a_,x_] = D[f1[a,x],x]]; ?f2 Global`f2 f2[a_, x_] = a^2*Cos[x] - a*Sin[x] I don't have a complete answer. The matter is complicated by Mathematica allowing replacement of symbols at particular places - so that Block[{a}, f[a]] could become Block[{b}, f[a]] or Block[{a}, f[b]].