2
$\begingroup$

Suppose I am given two positions, as well as b[0, 0] and b[0, 1]/Sqrt[2] + b[1, 1]/Sqrt[2], where b is some undefined symbol, so that the expressions remain in an unevaluated form. I would like to create the following rule: whenever the argument of b in position 1 is 0 and the argument in position 2 is 0, replace this using the latter expression. For example, let's say the positions are just the first and second arguments, and I have several expressions of the form b[x,y,z]. Looking at what I am given, I can manually write down the rule like below.

rule=b[0, 0, x_] -> b[0, 1, x]/Sqrt[2] + b[1, 1, x]/Sqrt[2]

Then I would have

b[0,0,0]/. rule
(*b[0, 1, 0]/Sqrt[2] + b[1, 1, 0]/Sqrt[2]*)

and

b[0,0,1]/.rule
(*b[0, 1, 1]/Sqrt[2] + b[1, 1, 1]/Sqrt[2]*)

Here's my attempt at creating the rule programmatically (I haven't gotten around to making this work for given positions yet, so assuming first and second argument).

rule=b[0, 0] -> b[0, 1]/Sqrt[2] + b[1, 1]/Sqrt[2] /. 
b[x_, y_] -> b[x, y, Blank[]]

But this doesn't give me what I want, because the Blank[] is not named and I don't know how to make it named since it is in the r.h.s. of the rule.

b[0,0,0]/. rule
(*b[0, 1, _]/Sqrt[2] + b[1, 1, _]/Sqrt[2]*)

Can anyone help?

$\endgroup$
6
$\begingroup$

If I understand correctly, what you need is to replace all of the occurrences of b[x, y] in a rule with b[x, y, z_] where x and y are constants and z is a pattern object to be matched. To start with, you need to use RuleDelayed (written as :>), then you use z_ on the right hand side, like this:

(b[0, 0] -> b[0, 1]/Sqrt[2] + b[1, 1]/Sqrt[2]) /. b[x_, y_] :> b[x, y, z_]
(*b[0, 0, z_] -> b[0, 1, z_]/Sqrt[2] + b[1, 1, z_]/Sqrt[2]*)

Though the output is still not quite right, as the output rule has z_ on the right hand side. So to fix this you need to match the pattern of the Rule, then modify the left and right separately, like this:

rule = (
  b[0, 0] -> b[0, 1]/Sqrt[2] + b[1, 1]/Sqrt[2]
) /. {
  Rule[left_, right_] :> RuleDelayed[
    Append[left, z_], 
    Evaluate[right /. {b[x_, y_] :> b[x, y, z]}]
  ]
} /. z$->z
(*b[0, 0, z_] :> b[0, 1, z]/Sqrt[2] + b[1, 1, z]/Sqrt[2]*)

To go through the elements:

  • The parenthesis at the start contain the rule you are modifying
  • Rule[left_, right_] matches to your rule
  • RuleDelayed makes a new rule (for the output)
  • Append[left, z_] adds the new pattern object z to the left hand side of the rule (using a ReplaceAll here does not substitute in the constants properly)
  • The Evaluate on the right hand side of the output replacement is because we are trying to output a RuleDelayed, meaning the right hand side will be left unevaluated by default.
  • /. z$->z at the end fixes an automatic substitution of z$ into your rule (to do with automatic scoping)

And to test:

b[0, 0, 1] /. rule
(*b[0, 1, 1]/Sqrt[2] + b[1, 1, 1]/Sqrt[2]*)

Note that you will need to make sure you clear z before you use this rule otherwise its value will be substituted in.

It's not the neatest solution but it should reliably do what you need.

$\endgroup$
  • 2
    $\begingroup$ +1, to avoid relying on z$ renaming you could go with something like Module[{h}, h[Append[left, z_], right /. {b[x_, y_] :> b[x, y, z]}] /. h -> RuleDelayed] $\endgroup$ – Kuba Nov 15 '16 at 12:47
3
$\begingroup$

Here's my swing at trying to solve this. First define this function:

ruleTransform[yourRule_] := 
  MapAt[
    Append[#, x_] &,
    yourRule,
    1
  ] /. b[a1_, a2_] :> b[a1, a2, x]

Next, you throw in the rule you want to change:

ruleTransform[b[0, 0] -> b[0, 1]/Sqrt[2] + b[1, 1]/Sqrt[2]]

This should give you the rule you needed.

$\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.