5
$\begingroup$

Say I have an expression

g=Sin[q];

It is easy to turn it into a function, and to perform manipulations on this function (this and variants of this were discussed many times on this site):

f[q_] = g;
fprime = Derivative[1][f];
fprime[3]
(*Output: Cos[3]*)

However, if I want to pass g as an argument to a function that will do that, this no longer works:

calculateDerivativeAt3[func_] := Block[{f, fprime},
  f[q_] = func;
  fprime = Derivative[1][f];
  fprime[3]
]
calculateDerivativeAt3[Sin[q]]
(*Output: 0 *)

How can I make this work in a similar way? The ultimate goal is to pass an expression into a function, and in the function to perform various functional manipulations, including derivatives, integrations, and more.

I'm pretty sure this question has an answer somewhere in this site, but I couldn't find it.

$\endgroup$
  • $\begingroup$ Can't you define calcDerAtq[func_, q_] := Derivative[1][func][q] and use it as calcDerAtq[Sin[#] Log[#^2/2] &, 10] ? $\endgroup$ – b.gates.you.know.what Aug 4 '15 at 13:43
  • $\begingroup$ I think you meant f[x_] = g (with x instead of a q). $\endgroup$ – Michael E2 Aug 4 '15 at 13:49
  • $\begingroup$ @MichaelE2 Fixed this issue in the question. $\endgroup$ – halirutan Aug 4 '15 at 14:11
4
$\begingroup$

The reason for your problem is the automatic renaming that Mathematica makes in cases where the names would clash. Let me give a very basic example (parenthesis for clarity; not required):

assign[rhs_] := (f[x_] := rhs)

What happens when you call assign[x^2] is that rhs contains the pattern variable x and Mathematica does a renaming so that no bad things happen.

assign[x^2];
?? f

Mathematica graphics

Do you see the difference between the renamed x$ and the pure x? Now it is obvious why this happens

f[3]
(* x^2 *)

and of course it's the same in your example. This whole approach is not how you should do it and I would rather use an approach like the one suggested by belisarius (and think about whether you need to prevent func or q from evaluation!):

calcDerAtq[func_, q_] := Derivative[1][func][q]

Since we now found the underlying reason for your code failure, I hope it is clear what is not a way to fix this issue (although it works):

calculateDerivativeAt3[func_] := Block[{f, fprime},
  f[q_] = func;
  fprime = Derivative[1][f];
  fprime[3]
  ]
calculateDerivativeAt3[Sin[q$]]
(* Cos[3] *)

If you like to use your function as it is, there is as simple way to prevent renaming. When you replace the line

f[q_] = func;

by the line

(f[q_] = #) &[func];

Mathematica is not able to detect the name-clash and cannot rename the variable. After this, you will get

Mathematica graphics

$\endgroup$
  • $\begingroup$ Thanks for your answer. The problem is that the solution that you recommend not to use is the one I need. The solution with calcDerAtq is specific to derivatives. What if I want to integrate the result, or plug it in NDSolve? $\endgroup$ – yohbs Aug 4 '15 at 21:20
  • $\begingroup$ @yohbs I have added a quick way how you can fix your function. Btw, this is not something you could have known. You'll learn which constructs will have surprising behavior and which won't. Look for instance here. A similar situation to yours, where the rhs injected by With changes everything. $\endgroup$ – halirutan Aug 4 '15 at 21:32
2
$\begingroup$

I gave a method for handling this kind of problem in this previous answer. Here I show its application to your problem.

expToF[exp_, vars : {(_Symbol | h_Symbol[_Integer]) ..}] := 
  With[{body = exp /. Thread[Rule[vars, Slot /@ Range@Length[vars]]]}, 
    Function[body]]

calculateDerivativeAt[xpr_, var_, val_] := Derivative[1][expToF[xpr, {var}]][val]
Clear[q]; calculateDerivativeAt[Sin[q], q, 3]
Cos[3]
$\endgroup$
1
$\begingroup$

I'm not sure how general this is, but it works here. Add another argument stating what the variable will be. Then replace the variable with a local variable inside your block.

calculateDerivativeAt3[func_, var_] := Block[
  {f, fprime, blkVar},
  f[blkVar_] = (func /. var -> blkVar);
  fprime = Derivative[1][f];
  fprime[3]
  ]
SetAttributes[calculateDerivativeAt3,HoldAll];
calculateDerivativeAt3[Sin[q], q]

This should give you the output you want. You'll want to set the attribute so the function still works if you happen to have an existing value for the variable you choose.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.