15

Suppose I have an expression containing p,Subscript[p,1],Subscript[p,2],etc. I want to replace p with a numerical value while keeping the other two variables intact. How can I do it?

If I naively use /.{p->0.5} for example, I will get Subscript[0.5,1], Subscript[0.5,2] as a result.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
wdg
  • 1,189
  • 9
  • 18

3 Answers3

26

You wish to make substitutions in all except Subscript expressions I believe. This can be done by leveraging the precedence of replacement rules, like this:

{p, Subscript[p, 1], Subscript[p, 2]} /. {x_Subscript :> x, p -> 1}
{1, Subscript[p, 1], Subscript[p, 2]}

Due to the traversal order of ReplaceAll the rule x_Subscript :> x acts first, "replacing" any expression with the head Subscript by itself. Since expressions that have already been replaced are not matched again, the second rule p -> 1 is never applied to these subexpressions.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
7

You could also make one rule that is a bit more specific

{p, Subscript[p, 1], Subscript[p, 2]} //. 
 head_[x___, p, y___] /; head =!= Subscript :> head[x, 0.5, y]

-> {0.5, Subscript[p, 1], Subscript[p, 2]}

This does not work if p is the entire expression. i.e

p/.head_[x___, p, y___] /; head =!= Subscript :> head[x, 0.5, y]

-> p

In that case you will probably have to add another rule. Note also ReplaceRepeated in the above may make things slower than necessary.

Side remark

You could also do something with Block as follows, though this is not replacement but rather evaluation

Block[
 {p = 0.5, Subscript},
 SetAttributes[Subscript, HoldAllComplete];
 {p, Subscript[p, 1], Subscript[p, 2]}
 ]

-> {0.5, Subscript[p, 1], Subscript[p, 2]}

Jacob Akkerboom
  • 12,215
  • 45
  • 79
  • This also has a problem if p exists twice in an expression for the same reason that my answer works. For example, with expression (p + p^2)/Subscript[p, 1]. I suggest amending your answer to use //. but that can be inefficient. – Mr.Wizard May 20 '13 at 12:55
  • @Mr.Wizard Thanks, I changed it. I guess in light of the new insights that Mathematica remembers if expressions have changed anyway, the "checking if the expression has changed" step of ReplaceRepeated must take negligable time. I suppose MMA just goes through the expression twice if use //., which is the same as in your answer where you use two rules. But then your rules are simpler, so your solution must be better in terms of speed, and I can see ever more desirable properties of your answer :). Anyway, +1 for you – Jacob Akkerboom May 20 '13 at 13:50
  • That was silly of me. It goes through the expression much more often. Changing – Jacob Akkerboom May 20 '13 at 13:52
  • 1
    +1 for the Block solution! A very nice addition. – Mr.Wizard May 20 '13 at 14:45
2

Another way is to use level specification in Replace :

Replace[{p, Subscript[p, 1], Subscript[p, 2]} , p -> 0.5, 1]
(* {0.5, Subscript[p, 1], Subscript[p, 2]} *)
b.gates.you.know.what
  • 20,103
  • 2
  • 43
  • 84