Skip to main content
added 1786 characters in body
Source Link
march
  • 24.2k
  • 2
  • 46
  • 102

###Two common examples

Complex numbers

An example of this that shows up quite often is when matching expressions with complex numbers. Some common examples are the following:

Cases[-I, I, Infinity]
(* { } *)
Cases[2 I, I, Infinity]
(* { } *)

The reason why I appears nowhere in those expressions is revealed when we look at the FullForm of the expressions:

I // FullForm
(* Complex[0, 1] *)
-I // FullForm
(* Complex[0, -1] *)
1 + 2 I // FullForm
(* Complex[1, 2] *)

All of these expressions are atoms; that is, they are all considered indivisible (structureless) objects in Mathematica (at least as far as pattern-matching is concerned).

Different fixes are useful for different use cases, of course. If one wants to manually conjugate a symbolic expression, one can do

expr /. z_Complex :> Conjugate[z]

If one wants to treat I as a symbol rather than as a complex number, one can do

Clear@i
expr /. Complex[a_, b_] :> a + i b

The moral is as above: it is often useful to look at the FullForm of an expression in order to design patterns for matching subexpressions.

Powers in the denominator

Consider the following:

enter image description here

The reason that the denominator gets replaced in the second case but not the first is revealed by looking at the FullForms of the expressions:

enter image description here

In the first case, the expression is internally represented with a negative power, but it is displayed as being the denominator of a fraction. Thus, the pattern _^2 is not matched, and so the expression is not replaced.

###Two common examples

Complex numbers

An example of this that shows up quite often is when matching expressions with complex numbers. Some common examples are the following:

Cases[-I, I, Infinity]
(* { } *)
Cases[2 I, I, Infinity]
(* { } *)

The reason why I appears nowhere in those expressions is revealed when we look at the FullForm of the expressions:

I // FullForm
(* Complex[0, 1] *)
-I // FullForm
(* Complex[0, -1] *)
1 + 2 I // FullForm
(* Complex[1, 2] *)

All of these expressions are atoms; that is, they are all considered indivisible (structureless) objects in Mathematica (at least as far as pattern-matching is concerned).

Different fixes are useful for different use cases, of course. If one wants to manually conjugate a symbolic expression, one can do

expr /. z_Complex :> Conjugate[z]

If one wants to treat I as a symbol rather than as a complex number, one can do

Clear@i
expr /. Complex[a_, b_] :> a + i b

The moral is as above: it is often useful to look at the FullForm of an expression in order to design patterns for matching subexpressions.

Powers in the denominator

Consider the following:

enter image description here

The reason that the denominator gets replaced in the second case but not the first is revealed by looking at the FullForms of the expressions:

enter image description here

In the first case, the expression is internally represented with a negative power, but it is displayed as being the denominator of a fraction. Thus, the pattern _^2 is not matched, and so the expression is not replaced.

oops, I corrected the definition of foo mid-write (the minus was always intended), but forgot to update it in the text ...
Source Link
celtschk
  • 19.2k
  • 1
  • 51
  • 107
foo = (a+b)(c+d)(e+fe-f)/Sqrt[2]
((a + b)*(c + d)*(e +- f))/Sqrt[2]
foo = (a+b)(c+d)(e+f)/Sqrt[2]
((a + b)*(c + d)*(e + f))/Sqrt[2]
foo = (a+b)(c+d)(e-f)/Sqrt[2]
((a + b)*(c + d)*(e - f))/Sqrt[2]
Source Link
celtschk
  • 19.2k
  • 1
  • 51
  • 107

The displayed form may substantially differ from the internal form

As soon as you discover replacement rules, you are bound to find that they mysteriously fail to replace subexpressions, or replace subexpressions you didn't expect to be replaced.

For example, consider the definition

foo = (a+b)(c+d)(e+f)/Sqrt[2]

which will cause Mathematica output an expression which looks very much like what you entered; approximately: $$\frac{(a+b)(c+d)(e-f)}{\sqrt{2}}$$ Also the InputForm seems to confirm that no transformation has been done to that expression:

((a + b)*(c + d)*(e + f))/Sqrt[2]

Now try to apply some rules on this (from now on I'll give the output in InputForm):

foo /. {x_ + y_ -> x^2 + y^2, x_ - y_ -> x^2 - y^2, Sqrt[2] -> Sqrt[8]}
(*
==> ((a^2 + b^2)*(c^2 + d^2)*(e^2 + f^2))/Sqrt[2]
*)

What is that? We explicitly requested the difference to be replaced with a difference of squares, not a sum! And why wasn't Sqrt[2] replaced at all?

Well, the reason is that Mathematica expressions are not what they look like. To see the real structure of a Mathematica expression, you can use FullForm:

foo // FullForm
(*
==> Times[Power[2, Rational[-1, 2]], Plus[a, b], Plus[c, d], 
     Plus[e, Times[-1, f]]]
*)

Now, we see why the replacement rules didn't work as expected: e-f is actually e + (-1)*f and thus matched perfectly the first rule (sum of two expressions) which transformed that into e^2 + ((-1)*f)^2 which of course evaluates to e^2+f^2. At the time the second rule is applied, the difference doesn't exist any more. Also, the Sqrt[2] in the denominator is actually a factor of 2^(-1/2). It is also easy to check that Sqrt[2] has Power[2, Rational[1, 2]] (that is, 2^(1/2)) as FullForm. That one is nowhere found in the FullForm of the expression foo evaluates to.

With that knowledge we can correct our replacement rules to work as expected:

foo /. {x_Symbol + y_Symbol -> x^2 + y^2,
        x_Symbol - y_Symbol -> x^2 - y^2,
        1/Sqrt[2] -> 1/Sqrt[8]}
(*
==> ((a^2 + b^2)*(c^2 + d^2)*(e^2 - f^2))/(2*Sqrt[2])
*)

First, we restricted our + rule to only accept symbols as expressions, so that it doesn't match e-f. For consistency, the same is true for the second rule. Finally, we replaced 1/Sqrt[2] instead of Sqrt[2] (Mathematica correctly evaluated 1/Sqrt[8] to 1/(2 Sqrt[2])).

Note that instead of FullForm you can also use TreeForm, which gives you a nice graphical representation of the internal expression).

Post Made Community Wiki by celtschk