Book Cover

Introduction to Scientific Programming
Computational Problem Solving Using:
Maple and C
Mathematica and C

Author:
Joseph L. Zachary
Online Resources:
Maple/C Version
Mathematica/C Version

Symbolic Computation Notebook

Click below to download a Mathematica notebook. You can look at the appended non-interactive HTML version of the notebook to learn what the notebook covers.

Symbolic Computation

This notebook is designed to accompany Chapter 6 of Introduction to Scientific Programming: Computational Problem Solving Using Mathematica and C by Joseph L. Zachary. In it we will explore the idea of symblic computing further.

Introduction

Chapter 6 only hints at the support for symbolic mathematics provided by Mathematica. In this notebook we will explore this support in more depth. The material that we will be covering here requires varying levels of mathematical expertise. Feel free to skip over examples if you don't have the necessary background.

Algebraic simplification

Mathematica's "Simplify" function expects an expression as a parameter, which it simplifies. For example, notice the difference between

     Sin[x]^2 + Cos[x]^2

and

     Simplify[Sin[x]^2 + Cos[x]^2]

Equation solving

Mathematica provides two general-purpose functions for solving equations, Solve and FindRoot. Solve works symbolically much as you do when solving equations; FindRoot works numerically by repeatedly guessing at a solution until it finds one that works. Solve is exact, FindRoot is approximate. For complicated equations, Solve can be much slower than FindRoot. In fact, there are plenty of equations where Solve fails but FindRoot succeeds.

Solve knows all kinds of tricks for solving equations. For example, it knows the quadratic formula

     Solve[3 * x^2 - 10 * x + 6 == 0, x]

With floating-point coefficients, we get floating-point solutions.

     Solve[3. * x^2 - 10. * x + 6. == 0, x]

Complex roots are also possible

     Solve[3 * x^2 - 4 * x + 6 == 0, x]

The coefficients can be entirely symbolic.

     Solve[a * x^2 + b * x + c == 0, x]

Mathematica can also solve simultaneous linear equations. Notice how list notation is used here.

     Solve[{3 * x + 4 * y == 7, 5 * x + 3 * y == 11}, {x, y}]

The equations don't have to be linear.

     Solve[{3 * x^2 + y == 7, 5 * x + 3 * y == 11}, {x, y}]

It is not difficult to pose an equation that solve cannot deal with.

     Solve[3 * Cos[x] == x, x]

If you don't need an exact or a symbolic solution, FindRoot can solve more equations and is generally faster.

     FindRoot[3 * Cos[x] == x, {x, 0}]

Of course, if you forget and pose a symbolic equation

     FindRoot[a * cos[x] == x, {x, 0}]

you'll get an error message.

Calculus

Mathematica is also handy for doing calculus. The D function does symbolic differentiation

     D[Cos[Sin[x]], x]

whereas the Integrate function does symbolic integration

     Integrate[-Sin[Sin[x]] * Cos[x], x]

You can also do definite integration by providing bounds

     Integrate[-Sin[Sin[x]] * Cos[x], {x, 0, Pi/2.}]

It is not difficult to stump Mathematica.

     Integrate[Cos[Sin[x]], x]

and this is how it tells you that it has failed. In situations like this, trying to do a definite integral as above may be futile as well.

     Integrate[Cos[Sin[x]], {x, 0, Pi/2.}]

In this case, if you "NIntegrate" instead, Mathematica will do a numerical integration. This means that instead of first integration symbolically and then plugging in the bounds, it will find an approximation to the integral without first computing the definite integral.

     NIntegrate[Cos[Sin[x]], {x, 0, Pi/2.}]

It is possible to supply infinity and -infinity as bounds. Thus

     Integrate[1/x, {x, 0, Infinity}]

diverges, whereas

     Integrate[1/Exp[x], {x, 0, Infinity}]

gives us a finite answer.

Replacements

Another handy feature of Mathematica is the ability to perform substitutions. Let's suppose that we solve an equation numerically

     soln = FindRoot[Cos[x] == x, {x, 0}]

We can substitute the value of soln for x in the left-hand-side of the equation by doing

     ReplaceAll[Cos[x], soln]

This works for any kind of expression. For example, suppose we differentiate

     res = D[Exp[Cos[x]], x]

and we'd like to find out the value of res when x is 1.2. We can do that with

     ReplaceAll[res, {x -> 1.2}]

When an equation has multiple solutions, it is possible to pick them out individually. Thus

     solns = Solve[3.15 * x^2 - 24.2 * x + 15 == 0, x]

We can access the first of the two solutions as

     solns[[1]]

and the second of the two solutions as

     solns[[2]]

Vectors and matrices.

Vectors and matrices are used extensively in linear algebra. Mathematica will do all of the standard operations on them.

Now we can define a vector with

     v = {1, 2, 3}

We can ask Mathematica to display the vector using more standard notation by using the function "MatrixForm".

     MatrixForm[v]

We can define a 3x3 matrix with

     m = {{1, 2, 3}, {4, 5, 4}, {3, 2, 1}}

and display it with

     MatrixForm[m]

Let's do some operations on vectors and matrices. We can do addition,

     StyleBox[{MatrixForm[v + v], MatrixForm[m + m]}, ShowStringCharacters -> True]

matrix multiplication,

     StyleBox[{MatrixForm[m . m], MatrixForm[m . v]}, ShowStringCharacters -> True]

and dot product

     MatrixForm[v . v]

We can transpose

     MatrixForm[Transpose[m]]

or invert

     StyleBox[{minverse = Inverse[m], MatrixForm[m . minverse]}, ShowStringCharacters -> True]

Much more is possible. Consult the on-line documentation for pointers.