4
$\begingroup$

I'm having a little trouble with substituting functions into an expression. A minimal example is as follows:

diffy := D[U[z], z];
Unevaluated[diffy]/. U[z] :> Exp[-I*k*z]
    Derivative[1][U][z]

Instead I want to do this:

Unevaluated[D[U[z], z]] /. U[z] :> Exp[-I*k*z]
    -I E^(-I k z) k

but obviously I can't do the latter because my practical "diffy" expression is a result of many steps and consists of many lines of functions and derivatives of U[z].

Is there a way Mathematica can take a function, substitute it into an expression such as "diffy" and evaluate it? I tried enclosing my expression above in "Evaluate[]" but that did not work.

Update: The solution provided works for the above prototype, but when I add another level, it all breaks down. This is a minimum example:

U0 := U[z];
diffy1 := Hold[D[U0, z]];
diffy1 /. U[z] :> Exp[-I*k*z] // ReleaseHold
    Derivative[1][U][z]

I have tried holding the first expression, releasing the hold in the definition of the second one and then holding again - and many other combinations of holding/releasing but nothing has worked so far. Is there a fundamental reason why this is not working? Maybe I'm not thinking of Mathematica correctly but I don't understand why this does not work immediately.

$\endgroup$
4
  • $\begingroup$ I don't know what is your goal at the end but with this setup you can Block[{U}, U[z_] := Exp[-I*k*z]; diffy] $\endgroup$
    – Kuba
    Commented Apr 21, 2014 at 19:57
  • 1
    $\begingroup$ Try diffy := Hold[D[U[z], z]]; then use diffy /. U[z] :> Exp[-I k z] // ReleaseHold. $\endgroup$
    – kale
    Commented Apr 21, 2014 at 20:01
  • $\begingroup$ Thanks kale! worked perfectly. I'm a little confused about the difference between a delayed set (:=) and the hold command. Are they fundamentally different? $\endgroup$ Commented Apr 21, 2014 at 20:04
  • 1
    $\begingroup$ := will evaluate at the time you reference the variable. Thus it will reevaluate every time you use it. For example: rnd := Random[]; {rnd, rnd, rnd}. Hold keeps the actual pattern unevaluated until you release it. $\endgroup$ Commented Apr 21, 2014 at 20:09

2 Answers 2

0
$\begingroup$

Based on your extended example I think you are going to need to change your fundamental approach to this problem, as it becomes too complicated to work out which parts should be evaluated and which should be held. (That is, for a general case.)

For the simpler example I recommend that you read How do I evaluate only one step of an expression? and my self-answer. Using step defined there we may write:

diffy := D[U[z], z];

step[diffy] /. U[z] :> Exp[-I*k*z] // ReleaseHold
-I E^(-I k z) k

(If you prefer you could also write: Unevaluated @@ step[diffy] /. U[z] :> Exp[-I*k*z])

This methodology breaks down however for your referential definition because nowhere is it specified which parts should and should not evaluate:

U0 := U[z];
diffy1 := D[U0, z];
step[diffy1] // FullForm
HoldForm[D[U0, z]]

For this particular example I presume you want only D to not evaluate, so you could Block it:

Block[{D}, diffy1 /. U[z] :> Exp[-I*k*z]]
-I E^(-I k z) k

If you always know which heads (functions) you wish to prevent from evaluating this is a fine method.


Evaluation by Context

Perhaps making only those substitutions described in definitions that exist in the Global` Context will have the effect that you desire. Please consider:

SetAttributes[evaluateGlobal, HoldFirst]

evaluateGlobal[expr_, supplemental_: {}] :=
  With[{values = {UpValues, NValues, OwnValues, DownValues, SubValues}},
    With[{rules = Flatten @ Outer[Apply, values, MakeExpression @ Names["Global`*"]]},
      Hold[expr] //. rules /. supplemental // ReleaseHold
    ]
  ]

This function allows either a one parameter input form, which will require manual holding:

U0 := U[z];
diffy1 := D[U0, z];

evaluateGlobal[Hold[diffy1]] /. U[z] :> Exp[-I*k*z] // ReleaseHold
-I E^(-I k z) k

Or a two parameter form to simplify its application for this use:

evaluateGlobal[diffy1, U[z] :> Exp[-I*k*z]]
-I E^(-I k z) k
$\endgroup$
10
  • $\begingroup$ Thanks, this makes sense but can I just tell it to not evaluate anything at all, and then plug in my expressions and then evaluate them? I thought this was what I was already doing. The problem with the "Block" approach is that I have many diverse types of terms in my actual application (imagine all combinations of up to third-order mixed derivatives in three variables) that are not particularly amenable to specifying separately, unless blocking "D" would block all of the D's (even the "double" D's). $\endgroup$ Commented Apr 22, 2014 at 19:53
  • $\begingroup$ @Ismail almost anything is possible so long as there is a clear algorithm to follow. Do I understand that you wish to evaluate (substitute) only your own definitions in the Global` context, while holding everything else as it is? $\endgroup$
    – Mr.Wizard
    Commented Apr 22, 2014 at 20:17
  • $\begingroup$ Mr. Wizard: I'm not sure what Global precisely means to be honest but I have a multi-step derivation in which I finally end up with an expression with high order mixed derivatives of U with respect to x, y, z. I'm a Mathematica novice and was under the impression that I could just derive everything and then "plug in" U(x,y,z) and let Mathematica do all the derivatives, etc. and "plug" them into the expression. I then realized that I have to "hold" the expression from being evaluated to do this procedure. I thought I was doing exactly this above but it seems I was wrong. What am I missing? $\endgroup$ Commented Apr 22, 2014 at 21:09
  • $\begingroup$ @Ismail Global` is the default context in which user Symbols (and therefore definitions) are created. By using only these definitions only your explicit transformations would be performed. I shall extend my answer to give an example of what I am proposing; please examine its behavior and tell me if it does what you need. $\endgroup$
    – Mr.Wizard
    Commented Apr 22, 2014 at 21:18
  • $\begingroup$ @Ismail Edit complete. $\endgroup$
    – Mr.Wizard
    Commented Apr 22, 2014 at 21:30
2
$\begingroup$

Holding the pattern works:

diffy := Hold[D[U[z], z]]
held = diffy /. U[z] :> Exp[-I*k*z]

Edit for completeness:

held // ReleaseHold
$\endgroup$
1
  • $\begingroup$ This worked perfectly, as Kale's suggestion as well! Thanks. $\endgroup$ Commented Apr 21, 2014 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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