Expressions

from Essential Mathematica for Students of Science
© James J. Kelly, 1998
Last revised: January, 2006

Initialization

ClearAll["Global`*"];
Off[General::spell,  General::spell1]

The machine behind the curtain

Introduction

Although there is often little reason to look too closely, sometimes we need to see the machine behind the curtain to understand the results of apparently simple operations which seem to go awry.  For example, if we try to simplify expressions involving only positive numbers using the elementary transformation

\(\(myrule = Sqrt[x_\^2] -> x;\)\)

we might be puzzled by the failure of this rule to give the obvious answer for this expression:

f = 1/Sqrt[(a^2)];
f /. myrule

We will return to this problem shortly and learn how to design rules which operate properly, but first we need to understand how Mathematica represents and manipulates expressions at a more basic level.

Every Mathematica statement, command, result, object, or symbol is an expression.  An expression can either be atomic (indivisible) or composite in nature.  Often the key to understanding what Mathematica does with an expression is to understand its internal representation for various types of expressions.  The front end hides the internal representation, offering instead representations that are generally more palatable to the human mind — the front end tries to tell you what it thinks you want to hear, but the underlying expression is all the kernel really knows about.  Several tools are available for displaying expressions either in their internal forms or some intermediate form.

The true nature of expressions is revealed using FullForm.  Using this function, we find that even a simple expression like a + b is really an expression of the form Plus[a,b].

FullForm[a + b]

Below we examine the structure of expressions as implemented by Mathematica.

Heads

The basic syntax for an expression takes the form f[stuff] where f is the head of the expression, identifying its type, and stuff is its contents.  Thus, to Mathematica all expressions look like functions or, equivalently, all functions look like expressions.  The consistency of the internal representation is largely responsible for the power of the language, with its flexibility arising from the variety of heads that are available.

Here Plus is the head of a + b and is a symbol that represents the built-in addition function.  We can obtain the head of an expression using Head[expr].

Head[a + b]

Head[Plus]

Although Mathematica contains built-in functions Subtract, Divide, and Sqrt which are convenient for input, those functions are considered redundant and are translated into more general forms based upon Plus, Times, and Power.

FullForm[Subtract[a, b]]

FullForm[Divide[a, b]]

FullForm[Sqrt[a]]

Replacement rules are vital components of Mathematica and are represented internally as

FullForm[a -> b]

To examine the internal representation of some expressions you need to intercept them before normal evaluation alters them.  For example, the expression

Clear[f];
FullForm[ f[a]  /. a -> b ]

is evaluated before we can look at it closely.  At better view is obtained by using  Hold[expr] to display an expression without evaluation.

expr  = FullForm[Hold[ f[a]  /. a -> b ] ]

Evidently, the operator /. is translated as ReplaceAll with the expression to its left becoming the first argument and the expression to its right the second.  Having named the result above, we can release the hold using ReleaseHold

ReleaseHold[expr]

HoldForm performs a similar function, but its head does not print in standard output form

1 + 1

Hold[1 + 1]

HoldForm[1 + 1]

This can be useful when we wish to present expressions in "natural order" rather than in the order used by Mathematica.  For example, Mathematica rearranges

a (x^2) + b x  +  c

but we might prefer to present the original order

HoldForm[a (x^2) + b x  +  c]

For the following exercises, predict the result by hand that you will obtain from Mathematica before executing Mathematica commands.  If your predictions are not accurate, be sure to understand the differences before proceeding to the next section.

Determine the internal representations of: 
a) a - 2b	b) a/b		c) (Sqrt[a])		d) (Sqrt[(a^2)])	e) a==b==c

Determine the full form of the equation (Sqrt[(x^2) - 4]) ==  (Sqrt[x + 1]).

Determine the internal representations of: 
a) a_		b) a__		c) a___	d) a..		e) {{_,_}..}	f) a:b

Determine the heads of the following expressions:
a) a_		b) a==b	c) _?x		d) a:b

Atoms

In Greek an atom is an indivisible object containing no parts, while in Mathematica an atom is an object containing raw data that carries a symbolic name identifying the data type.  Thus, a Mathematica integer is an atom with head Integer containing the machine representation of an integer.

Head[Symbol]

Head[1]

Head[Integer]

The atomic objects are Symbol, String, Integer, Real, Rational, and Complex and each contains raw data of the specified type.  The function AtomQ tests the atomicity of an expression.

AtomQ /@ {Ψ, "blessed be the meek", -2, π, 
        (1/3), 1 + I π}

Why did the complex number at the end of this list fail the test of atomicity?  Use FullForm to look more closely at this expression.

FullForm[1 + I π]

This expression is not atomic because its head is Plus, not Complex.  In fact, Complex appears only where I is finally multiplied by Pi.

{FullForm[I],  FullForm[Pi]}

{Head[I], Head[Pi]}

The internal representation of the unit complex number, I, leads to some subtleties for performing complex arithmetic using Mathematica.  For details, please consult the notebook complex.nb.

Parts of expressions

The contents of nonatomic expressions can be extracted and manipulated using self-explanatory functions like Part,  First, Head, Last, Extract, Position, ReplacePart, MapAt, and Take.  Many of these functions act on both expressions and lists in similar ways.  Rather than repeat detailed explanations of syntax available in the reference guide, a few simple examples should suffice.

Clear[a, b, c, x, f];
f  =  a (x^2) +  b x  +  c;

FullForm[f]

Head[f]

Table[Part[f, n], {n, 0, 3}]

{First[f], Last[f]}

\(\(\( (*\ counting\ from\ end\ *) \)\(
\)\({Part[f, \(-1\)], 
      Part[f, \(-2\)]}\)\)\)

FullForm[Part[f, 3]]

\(\(\( (*\ first\ and\ third\ parts*) \)\(
\)\(Part[
      f, {1, 3}]\)\(\ \)\)\)

Notice here that the head Plus is retained, so that the parts we selected are summed.

\(\(\( (*\ second\ part\ of\ third\ part\ *) \)\(
\)\(Part[f, 3, 
      2]\)\)\)

\(\(\( (*\ 
      complete\ addresses\ for\ occurrences\ of\ x\ *) \)\(
\)\(Position[f, 
      x]\)\)\)

The list above contains part specifications for each occurrence in a recursive form.  Thus, {3,2,1} indicates the first part of the second part of part 3.

ReplacePart[f, "(x used to be here)",  {3, 2, 1}]

Parts of an expression can also be replaced by reassigning the value of a particular part.

f

f[[2, 1]] = bnew; f

Sometimes it is helpful to use TreeForm to examine the structure of an expression.  For example, the following equation contains two main parts, the left-hand side and the right-hand side, each of which in turn contains a subpart with subsubparts.

TreeForm[(Sqrt[(x^2) - 4]) == (Sqrt[x + 1])]

In using these functions, it is important to realize that Mathematica has its own scheme for ordering the parts of expressions and that scheme does not necessarily agree with your notions of natural ordering.  You must be careful when using part specifications because what you see is not necessarily what you'll get.

For the following exercises, predict the result by hand that you will obtain from Mathematica before executing Mathematica commands.  If your predictions are not accurate, be sure to understand the differences before proceeding to the next section.

List all subexpressions in (∫_a^b) f[x] dx with their position specifications.   What is the address of b?  In what positions does x occur?

Use ReplacePart to replace the expressions under the square roots signs in the equation  (Sqrt[(x^2) - 4]) ==  (Sqrt[x + 1]) by lhs and rhs.

Attributes

Symbols have Attributes which govern their behavior.  Atomic data types are all Protected, which prevents their values from being changed (you can't change π to 3.14 anywhere outside Tennessee!).  In addition, symbols can be Locked to prevent their attributes from being changed.

Attributes /@ {Symbol, String, Integer, Rational, Real, 
        Complex}

Common arithmetic functions have additional attributes.

Attributes /@ {Plus, Times, Power}

For a complete list of attributes please refer to the reference guide or to Section 2.6.3.  For our purposes, some of the most important attributes are:

Orderless confers the commutative property by ensuring that the order of arguments is immaterial, such that f[a,b]=f[b,a].  For example, Plus[a,b]=Plus[b,a].

Flat confers the associative property by flattening arguments such that f[a,f[b]]=f[a,b].  Thus, Plus[a,Plus[b,c]]=Plus[a,b,c] and Times[a,Times[b,c]]=Times[a,b,c].

OneIdentity ensures that f[f[a]] matches f[a].  This attribute is needed for functions like Plus or Times so that Plus[a]=a and Times[a]=a.

Listable indicates that a function is automatically "threaded" over lists; in other words, that a listable function given a list of its argument returns a list of evaluations for each input element.  Many Mathematica functions are listable.  Functions that you write using listable functions will often behave listably even without explicitly conferring that attribute.

Clear[f];
f[x_] := Sin[x]/x

f[{1, 2, 3, 4, 5}]

Another important attribute is Constant, meaning that all derivatives vanish.  Thus, when evaluating a total differential

Clear[a, m, x, y, z];
a = (( (ℏ^2))/(2 m)) ψ[x, y, 
            z];

Dt[a]

we might like to declare Planck's constant and the mass to be constant using SetAttributes.

SetAttributes[{ℏ, m}, Constant];

Dt[a]

Later, when we clear values and definitions associated with m

Clear[m]

?m

we should be aware that Clear does not alter the attributes of a symbol.  To make a clean sweep of values and attributes, we must use ClearAll.

ClearAll[m]

?m

When we define our own functions, we may need to consider the appropriate attributes to bestow upon them.  Note that attributes should be chosen before definitions are given.  In the following example we create a noncommutative multiplication function using the ⊗ operator.

ClearAll[f, a, b];
SetAttributes[
        f, {Listable, OneIdentity, Flat}];
f[a_, b_] := a⊗b;

f[a, b]

f[a, b, c]

f[c, f[a, b]]

f[a, {b, c, d}]

f[{a, b}, {c, d}]

Generalize the example above to ensure that f[a, 2b]->2a⊗b and f[a+b,c]->a⊗c+b⊗c.  Supply definitions and test other reasonable variations of this noncommutative function.  [Hint: you might find Trace helpful in interpreting the evaluation procedure.]

Explain the output for the following expressions.   [Be sure to clear a,b,c first.]
a) Dot[a,b]==Dot[b,a]
b) Dot[Dot[a,b],c]
c) Dot[Dot[a,b],c]==Dot[a,Dot[b,c]]

Swapping heads

Just like the colloquialism "I swapped my head", meaning "I changed my mind", Mathematica heads can be changed.  Suppose that I have a list of numbers

a  =  {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Head[a]

and later want the sum of those numbers.  That is easily accomplished by replacing the head List with the head Plus

a /. List -> Plus

However, if an expression contains several occurrences of the head to be changed, the ReplaceAll operator /. may be too powerful because it acts at all levels while we may want to change only the top level.  The next example includes a function which takes a list as its argument — we probably would not want to replace its argument when forming the sum of these elements.

{3, η[{b, c, d}],  -7,  f + g}  /. 
      List -> Plus

A better way to transform a List into a function of its elements is provided by the function Apply[f,list], also represented by the operator notation f@@list, which has the effect of replacing List by f at the top level only.

Apply[Plus, a]

Plus @@ a

Plus @@ {3, η[{b, c, d}],  -7,  
        f + g}

somefunction @@ a

Another head replacement transforms a rule into an equation.

Clear[x, y, f];
rule1  =  y -> f[x];

rule1 /. Rule -> Equal

Generate a list of 10 random numbers using Random.  Find the sum and product those numbers by swapping heads.

Evaluate (∑_(n = 1)^50) (1/(((2  n + 1))^2)) using Apply, Range, and listability of arithmetic functions; use Sum only to check afterward.

Manipulating equations

Using Thread and Map

Consider the generic equation

eq1  =  lhs  ==  rhs

Suppose that we wish to square both sides.  Unfortunately, the obvious method

(eq1^2)

does not work because it simply squares an expression without regard to its meaning.  There are several methods for performing such operations that depend upon understanding the internal representation of expressions of this type.

FullForm[eq1]

FullForm[(eq1^2)]

The problem arises because Power is wrapped around the entire expression for eq1 rather than the two subexpressions that are found as arguments of Equal.  We can instruct Mathematica to "thread" a function through a head and apply it to the subexpressions at the next level using the function Thread.  The syntax Thread[f[args],head] is used to thread the function f through any head that appears in the arguments args of f.  Since the default value of the second argument is List, we can omit the second argument when using Thread to access the elements of a list.  We can express the desired function either as a pure function in skeletal notation (see functions.nb for explanation of this technique)

\(Thread[\(#\^2 &\)\ @eq1, Equal]\)

or as an explicit function

Thread[Power[eq1, 2], Equal]

or in a short-hand notation

Thread[(eq1^2), Equal]

Similarly, suppose that we have two lists of the same length

list1  =  {lhs1, lhs2, lhs3};
list2  =  {rhs1, rhs2, rhs3};

and wish to create a system of equations from the elements of each list.  Although

list1 == list2

does not work,

Thread[list1 == list2]

does.

Closely related is Map, with convenient operator notation /@, which maps a function onto subexpressions.  In the form f/@expr or Map[f,expr] the function f is applied to each subexpression at the first level of expr.  Thus, we can square both sides of an equation using the compact, but punctuation infested, statement

\(\(#\^2 &\) /@ \ eq1\)

Write compact statements for: 
a) adding the same quantity to both sides of an equation, 
b) exponentiating both sides, 
c) applying an arbitrary function f to both sides.

Use Map and head swapping to transform an equation of the form (Sqrt[lhs]) == (Sqrt[rhs]) into an equation of the form lhs - rhs == 0.  (Note that Simplify will not do what we seek by itself!)

Use Map and an appropriate skeletal function to transform the equation y == (1/(a  +  b Exp[-(t^2)])) into an equation of the form Exp[(t^2)] == rhs where rhs is the appropriate right-hand side of the new equation.  Then use Map on the new equation to solve for t.

Example: Compton scattering

Suppose that a photon with initial momentum (Subscript[p, i]) scatters from a stationary electron with mass (Subscript[m, e]), such that the scattered photon emerges at angle θ with final momentum (Subscript[p, f]) while the electron emerges at angle ϕ with momentum (Subscript[p, e]).  Application of the principles of conservation of energy and momentum gives the following system of equations.

\(\(eqs\  = \ {
		p\_i == 
            p\_f + K, 
		\(p\_e\) Cos[ϕ] == 
            p\_i - \(p\_f\) Cos[θ], 
		\(p\_e\) 
              Sin[ϕ] == \(p\_f\) 
              Sin[θ], 
		p\_e\^2 == \((m\_e + K)\)\^2 - 
              m\_e\^2
	};\)\)

Here K is the kinetic energy of the electron and we are using units for which ℏ = c = 1.  Although this system of equations can be solved fairly easily by hand, if you attempt to do it using the most obvious Mathematica function

Solve[eqs, {(Subscript[p, f]), (Subscript[p, e]), K, ϕ}]

your computer will grind practically forever without producing a solution and you will need to abort the evaluation.  [Hence, the cell above was made nonevaluatable to avoid accidental execution.]  Without the benefit of human insight, the program fails to recognize that ϕ can be eliminated by squaring and adding the second and third equations.  Nor does the Eliminate function help (try it!).  Therefore, you need to provide the computer some guidance.

The following transformation squares the second and third equations first, then brings the right-hand sides to the left (Equal->Subtract), adds the two resulting expressions, and finally forms a new equation for which ϕ has been eliminated.  Note that the parentheses are needed to ensure that the operations are performed in the proper order.  Also note that we avoid cross terms in ϕ by squaring before the two sides of each equation are combined.  Take this apart and make sure that you understand how it works!

\(eq1 = \((\((\(#\^2 &\) /@ \ 
                    eqs[[2]])\) /. 
                Equal -> 
                  Subtract)\) + \((\((\(#\^2 &\) /@ \ 
                    eqs[[3]])\) /. 
                Equal -> Subtract)\) == 0 // Simplify\)

Mathematica can now solve the following reduced system of equations without difficulty.

newEqs = {eq1, eqs[[1]], 
        eqs[[4]]}

sol = Solve[
            newEqs, {(Subscript[p, f]), (Subscript[p, e]), 
              K}][[1]] // 
        Simplify

Finally, recognizing that the wavelength of a photon is the reciprocal of its momentum (in units where  ℏ = c = 1), we obtain the familiar Compton shift formula

(1/(Subscript[p, f])) - (1/(Subscript[p, i])) /. sol // Simplify

As powerful as it is, Mathematica cannot replace thought!  Although the syntax of these manipulations takes some familiarization, it is really not much different from the manipulations that you would perform by hand.  Using Mathematica you must specify the rules and let the machine execute the operations, whereas in hand calculations you must use the same rules to execute the operations yourself even if you do not formulate those rules explicitly.  By formulating rules carefully instead of performing explicit manipulations, you can assemble very large symbolic calculations and can test variations without having to repeat many tedious and error-prone manipulations.

Pattern matching

Pattern templates

Mathematica recognizes the practically unlimited variety of patterns that can be constructed from the templates described in the following table.

({{Pattern Templates}, {({{pattern, description}, {_, matches any expression}, {x_, any expression,  referred to as x}, {x_h, any expression with head h}, {x_ /; cond, any expression satisfying a condition}, {pattern?test, \(pattern\ which\ yields\ true\ when\ test\ is\ applied\)}, {x__, \(a\ sequence\ of\ one\ or\ more\ expressions\ collectively\ named\ x\)}, {x___, \(a\ sequence\ of\ zero\ or\ more\ expressions\ collectively\ named\ x\)}, {x___h, \(a\ sequence\ of\ zero\ or\ more\ expressions\ , all\ with\ head\ h, collectively\ named\ x\)}, {x_:  def, optional pattern with default value}, {x_., pattern with built - in default}, {x_h:  def, \(expression\ with\ head\ h\ and\ default\ value\ def\)}, {x : patt, \(expression\ named\ x\ matching\ \ pattern\ patt\)}, {x^n_, any power of x}, {x_^n_, any power of any expression}, {{x_, y_}, a list of length 2}, {{x_, x_}, a pair of identical elements}, {pattern .. , \(one\ or\ more\ repeated\ elements\ of\ a\ specified\ pattern\)}, {pattern ... , \(zero\ or\ more\ repeated\ elements\ of\ a\ specified\ pattern\)}, {{{_, _} .. }, a list of one more lists of length 2}, {f[x_], function f with any argument named x}, {f_[x_], any function of any argument}, {patt1 | patt2, \(pattern\ with\ two\ or\ more\ alternative\ forms\)}})}})

Since it is impossible to list all possible permutations, we give only the basic templates — many additional patterns can be constructed by combining these elements appropriately.  For example, the table defines _h to be any expression with head h and defines {{_,_}..} to be a list containing one or more pairs of elements.  Thus, we can construct a pattern which matches a list of one or more integer triplets as {{_Integer,_Integer,_Integer}..} even though that pattern does not appear within the table.

mypatt  =  {{_Integer, _Integer, _Integer} .. };

The following list contains several elements which match the pattern and several which do not.

mylist =  { {1, 2, 3}, {{1, 2, 3}},  {{1, 2, 3}, {-5, 0, 8}}, 
          x, {{1, 2, 3}, {1. , 2. , 3. }} };
mylist // ColumnForm

We can test each element of the list against the specified pattern by mapping MatchQ[#,pattern]& onto the list; this operation then returns a list of true or false results.

MatchQ[#, mypatt] &  /@  mylist

Alternatively, we can use Cases[list,pattern] to select the elements matching the pattern, obtaining therefrom a shorter list.

Cases[mylist, mypatt]

Evaluate the following expressions and explain the results.
a) MatchQ[a - b c, x_ - y_]	b) MatchQ[a - b c, x_+y_]
c) MatchQ[a - 2 c, x_ - y_]	d) MatchQ[a - 2 c, x_+y_]

Determine the full form of the following expressions.
a) a|b		b) a_|b_	c) a_Rational | a_Integer

The following function will be helpful in testing patterns against a list of test cases.  Be sure to predict which members of each list of test cases should match the specified pattern and which should not.  If your results differ, you will need to sharpen your pattern definition.

CheckPattern[data_, pattern_] := 
      Transpose[{data, MatchQ[#, pattern] &  /@ data}] // 
        MatrixForm

Write a pattern for a list of one or more strings.  Which elements of the following list match the pattern?  Why do the others fail?
	{x, "good morning", {"red", "green", "blue"}, {"Help!"},{"one",2,"three"}}

Write a pattern for simple expressions with rational exponents.  Which elements of the following list match the pattern?  Why do the others fail?  Generalize the pattern to include integer exponents as well  [hint: use the alternative pattern operator | ].
	{x, (a^b), (x^(1/2)), (x^2),3, a + (b^(3/4)), (y^π), z (z^(1/8))}

Write a pattern for real or complex numbers with nonnegative real parts.  In addition to obvious test cases, make sure it handles cases like 3 - i π correctly.

Write a pattern for complex numbers whose real and imaginary parts are integers.   Which elements of the following list match the pattern?  Why do the others fail?  Generalize to include real integers, which are indeed special cases of complex numbers composed of integers.
	{a + I b, I, -3 + 2  I, 14, 3 + I/2}

Write a GaussianIntegerQ function which returns True for a Gaussian integer or False otherwise.  Recall that a Gaussian integer is a complex number whose real and imaginary parts are both integers, with real integers comprising a subset of the Gaussian integers.  [Hint: use FullForm to identify the appropriate patterns and MatchQ to compare the argument with those patterns.]

Patterns with built-in defaults

Patterns based upon arithmetic operations often have built-in defaults.  For example, the pattern a+b_. indicates a sum of two elements for which the second element may vanish and hence be absent.  Thus, a single term matches this pattern

MatchQ[a,  a_ + b_. ]

but would not match the very similar pattern a_+b_ that does not include the built-in default.

MatchQ[a,  a_ + b_]

Obvious defaults are 0 for addition or 1 for multiplication or powers.

Write a pattern for a difference between two symbols, a - b, that also recognizes cases like {a - 2, a - 2  b, f[x] - g[x]} as special cases while rejecting cases like {a, a + b, a + 2  b, f[x] + g[x]}.

Role of attributes in pattern matching

The attributes of a symbol often play a crucial role in its pattern-matching behavior.  If we define a function without specifying its attributes

ClearAll[f];
Attributes[f]

the order of its arguments is considered when comparing against a pattern.

MatchQ[ f[1, x], f[x_, 1] ]

By contrast, the built-in function Plus matches for any order of its arguments because it has the attribute Orderless.

Attributes[Plus]

MatchQ[Plus[1, x],  Plus[x_, 1] ]

We can bestow similar behavior on our function by setting its attributes

SetAttributes[f, Orderless];

and we then obtain a match for either order of the arguments.

{MatchQ[ f[1, x], f[x_, 1] ],  
      MatchQ[ f[x, 1], f[x_, 1] ] }

Orderless functions may match a pattern in several possible ways and Mathematica uses the first match it encounters.  For example, the following replacement rule eliminates a repeated argument from an orderless function, but if there are several repeated arguments it is not always obvious which one will be eliminated.

Clear[f, a, b, c, d]

f[a, b, c, b, a] /. f[a_, a_, b___] -> f[a, b]

f[b, a, c, a, b] /. f[a_, a_, b___] -> f[a, b]

Of course, ReplaceRepeated can be used to eliminate all repetitions.

f[a, b, c, b, a] //. f[a_, a_, b___] -> f[a, b]

f[a, a, a] //. f[a_, a_, b___] -> f[a, b]

Think like a computer

At the beginning of this notebook we discovered that the obvious transformation rule

\(\(myrule = Sqrt[x_\^2] -> x;\)\)

fails to produce the expected result for the following expression:

f = 1/Sqrt[(a^2)];
f /. myrule

Why didn't this work?  First, look a little more closely at the rule we defined.

FullForm[myrule]

Nowhere in this rule does Sqrt actually appear.  Mathematica allows us to enter input using the familiar square root function, but internally it uses Power[#,Rational[1,2]].  This works for

(Sqrt[(a^2)]) /. myrule

because the same conversion is made here before the rule is applied

FullForm[(Sqrt[(a^2)])]

but for

FullForm[(1/((Sqrt[a])^2))]

we find that the internal representation involves Power[#,Rational[-1,2]] which is not covered by the rule.

Central concept: Mathematica transforms expressions according to rules associated with symbols and patterns.

Given an expression, Mathematica scans each subexpression for symbols and patterns that it recognizes, searches its tables for rules that apply to each symbol and pattern it finds, performs the specified transformations, and repeats as necessary.  If it doesn't find a matching pattern, no transformation is performed.  Unfortunately, people are much better at recognizing patterns than in formulating rigorous rules for those patterns.  I can't tell you what makes music good, but I know good music when I hear it!  Computers, on the other hand, are idiot savants — they can't formulate rules for themselves, but can do what they're told at lightning speed.  The problem is that they do what they are told, neither more nor less nor perhaps what you actually intended.  Do what I mean, damn you, not what I say!.

Researchers in artificial intelligence attempt to produce mechanical models which simulate the behavior of living organisms and ultimately hope to create machines which think like humans, but faster.  Their crowning achievement, after several decades of intensive work, is a mechanical cockroach!  It will obviously take many more decades, perhaps even centuries, before computers achieve the type of insight and creativity that is distinctively human.

Since you can't make the computer think like you, you will have to learn to think like the computer.  This entails understanding the pattern-matching algorithms well enough to predict when the program will recognize that an expression matches a particular pattern and to formulate patterns and rules rigorously enough for successful mechanical processing without benefit of human insight.  For the example suggested above, the more general rule

\(myrule2\  = \((x_\^n_)\)\^m_ -> x\^\(n\ m\)\)

covers that case and many others (provided , of course, that the variables are known to be positive)

{(1/((Sqrt[a])^2)), (((8/(a^6)))^(1/3)), (((((b^2) (c^9))/((a^6) (d^(-4)))))^(1/3))} /. myrule2

but is still not sufficiently general to do anything with the third expression above.

Some of the important tools for developing and debugging transformation rules are: FullForm, MatchQ, and Trace.  MatchQ[expr,pattern] compares an expression with a pattern, returning True for a match or False otherwise.  Trace[expr] displays the evaluation sequence in a relatively terse format; more elaborate traces can be obtain with related functions.

It should not be surprising that this expression does not match the pattern specified by myrule2:

\(MatchQ[\@\(\(\(b\^2\) c\^9\)\/\(a\^6\ d\^\(-4\)\)\)\%3, \((x_\^n_)\)\^m_]\)

When we trace the evaluation of this expression, we find that the first few steps transform the input form into standard form before attempting to apply the rule.

Trace[(((((b^2) (c^9))/((a^6) (d^(-4)))))^(1/3)) /. 
        myrule2]

The expression we seek to simplify is actually represented as (product of terms) raised to a rational power.

FullForm[(((((b^2) (c^9))/((a^6) (d^(-4)))))^(1/3))]

The product serves as an x_ pattern, so that

\(MatchQ[\@\(\(\(b\^2\) c\^9\)\/\(a\^6\ d\^\(-4\)\)\)\%3, 
      x_\^n_]\)

is already as simple as our rule requires.  If we had wanted the expression to be expanded, we should have said so in the first place!  This is easily done by generalizing the rule to include products.  Note that the pattern a_. used in a product indicates a factor with built-in default value of unity, which ensures that b will match the pattern a_. b_ in which the unit factor does not appear.  Repeated replacement using our more general pattern then achieves the desired expansion.

\(\(myrule3\  = \((a_. \ x_\^n_)\)\^m_ -> \(a\^m\) 
            x\^\(n\ m\);\)\)

(((((b^2) (c^9))/((a^6) (d^(-4)))))^(1/3)) //. myrule3

The expressions (1 + 2  x + (x^2)) and (((1 + x))^2) are obviously equal, but does (1 + 2  x + (x^2)) match the pattern (((1 + x_))^2)?.  If not, why not?

Formulate a rule or set of rules which will combine all of the following expressions into single expressions of the form Log[expr].
a) n Log[x] 	b) Log[x]+Log[y]+Log[z]	c) Log[x] - Log[y]+Log[z]	d) m Log[x] - n Log[y]

Suppose that we are given a polynomial of the form poly = 
        a  + b x + c (x^m) + d (x^n) +  ⋯.  Use Switch to write a function PolyTerms[poly,x] which will return a list of exponents and coefficients with the form {{0,a},{1,b},{m,c},{n,d},⋯}.  Be sure to test a variety of expressions.

Expressions representing cells

The cells comprising a notebook are also represented as expressions.  Even notebooks themselves are expressions with head Notebook.  Notebooks live in the computer as ascii files containing only a sequence of alphanumeric and other simple symbols, each of which at a lower level is represented as a binary code.  Yet on the monitor we see formatted text, cell markers, background colors, a variety of plots, tool bars and icons, perhaps some figures, etc.  It worth examining how some of these structures appear in the notebook file.

Select a cell by clicking on its cell bracket.  Then, either using the menu sequence Format ↦ Show Expression or the key sequence Shift Ctrl E, display the expression representing the cell.  Simply repeat to undo.

By examining the expressions that represent cells you will find text of the general form Cell["contents","type"].  Not surprisingly, a "Text" cell contains a text string.  The "Exercise" cell above contains TextData that includes some special characters in verbose form, such as TextData["\RightTeeArrow]"].  Note that we wrapped the ascii form in a TextData function to prevent the front end from automatically converting to the graphical form usually displayed.   Now look at the expressions shown below as a simple statement that generates a plot and the plot itself.  The input cell is represented by a Cell function whose arguments are a BoxData function, a cell type string, and a rule for replacing the label.  The argument of the BoxData  consists of many nested RowBox functions each carrying elements of the expression in excruciating detail.  Nevertheless, sometime it is easier to edit the underlying ascii text (after using Show Expression) than to use the Options Inspector provided by the front end.  This can also be handy for modifying hyperlinks.
Graphics are also represented by ascii text, usually in the form of postscript.  Thus, despite the relative simplicity of the accompanying figure, its postscript representation requires an impressive mass of ascii characters.  No wonder that notebooks containing nontrivial graphics consume so much disk space!

Plot[Evaluate[Gamma[x]], {x, -5, 5}, 
        PlotRange -> {Automatic, {-10, 10}}];