... until the collector arrives ...

This "blog" is really just a scratchpad of mine. There is not much of general interest here. Most of the content is scribbled down "live" as I discover things I want to remember. I rarely go back to correct mistakes in older entries. You have been warned :)

2012-09-06

Mathematica: Beware Orderless Patterns

Consider the following Mathematica pattern transformation:

In[1]:= 2 x /. a_ b_ :> {a, b}
Out[1]= {2, x}

No surprises there. But watch what happens if you change the pattern variable a to z:

In[2]:= 2 x /. z_ b_ :> {z, b}
Out[2]= {x, 2}

The result elements are reversed, just because a variable was renamed. What happened?

This behaviour is by design. It occurs because of two points. The first is that the patterns on the left-hand side of replacement rules are evaluated. In this case, z_ b_ will be evaluated. The second point is that * (Times) has the attribute Orderless. This means that the arguments to the function are sorted into canonical order prior to evaluation. We can see the effect of this canonical ordering on the replacement rule that uses z_:

In[3]:= z_ b_ :> {z, b}
Out[3]= b_ z_ :> {z, b}

The pattern is reversed. This explains the difference between the two replacements. Is there anything we can do to avoid this? Well, we could hide the Times operator from evaluation:

In[4]:= 2 x /. Verbatim[Times][z_, b_] :> {z, b}
Out[4]= {2, x}

This "works", but is fragile. In a toy example like this, we can control the points where the pattern gets evaluated. But in more realistic examples, it is easy to accidentally evaluate the relevant part of the pattern, resulting in the variable swap. So the bottom line is that one must be very careful when writing patterns involving orderless operators. Especially when the pattern is being used to transform the orderless operator into an operator that is sensitive to order. Note that this problem would not be observed if the target operator were orderless as well:

In[5]:= 2 x /. a_ b_ :> a + b
Out[5]= 2 + x
In[6]:= 2 x /. z_ b_ :> z + b
Out[6]= 2 + x

Blog Archive