Maxima by Example Woollett Complete
Maxima by Example Woollett Complete
Contents
1.1
1.2
1.3
What is Maxima? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Which Maxima Interface Should You Use? . . . . . . . . . . . . . . . . . . . . . . . . . . .
Using the wxMaxima Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.3.1 Rational Simplification with ratsimp and fullratsimp . . . . . . . . . . . . . . . . .
1.4 Using the Xmaxima Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.5 Creating and Using a Startup File: maxima-init.mac . . . . . . . . . . . . . . . . . . . . . .
1.6 Maxima Expressions, Numbers, Operators, Constants and Reserved Words . . . . . . . . . .
1.7 Input and Output Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.8 Maxima Power Tools at Work . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.8.1 The Functions apropos and describe . . . . . . . . . . . . . . . . . . . . . . . . . .
1.8.2 The Function ev and the Properties evflag and evfun . . . . . . . . . . . . . . . . . .
1.8.3 The List functions and the Function fundef . . . . . . . . . . . . . . . . . . . . . . .
1.8.4 The Function kill and the List values . . . . . . . . . . . . . . . . . . . . . . . . . .
1.8.5 Examples of map, fullmap, apply, grind, and args . . . . . . . . . . . . . . . . . . .
1.8.6 Examples of subst, ratsubst, part, and substpart . . . . . . . . . . . . . . . . . . .
1.8.7 Examples of coeff, ratcoef, and collectterms . . . . . . . . . . . . . . . . . . . . . .
1.8.8 Examples of rat, diff, ratdiff, ratexpand, expand, factor, gfactor and partfrac . . .
1.8.9 Examples of integrate, assume, facts, and forget . . . . . . . . . . . . . . . . . . . .
1.8.10 Numerical Integration and Evaluation: float, bfloat, and quad qags . . . . . . . . . .
1.8.11 Taylor and Laurent Series Expansions with taylor . . . . . . . . . . . . . . . . . . .
1.8.12 Solving Equations: solve, allroots, realroots, and find root . . . . . . . . . . . . . .
1.8.13 Non-Rational Simplification: radcan, logcontract, rootscontract, and radexpand . .
1.8.14 Trigonometric Simplification: trigsimp, trigexpand, trigreduce, and trigrat . . . . .
1.8.15 Complex Expressions: rectform, demoivre, realpart, imagpart, and exponentialize
1.8.16 Are Two Expressions Numerically Equivalent? zeroequiv . . . . . . . . . . . . . . .
1.9 User Defined Maxima Functions: define, fundef, block, and local . . . . . . . . . . . . . . .
1.9.1 A Function Which Takes a Derivative . . . . . . . . . . . . . . . . . . . . . . . . . .
1.9.2 Lambda Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.9.3 Recursive Functions; factorial, and trace . . . . . . . . . . . . . . . . . . . . . . . .
1.9.4 Non-Recursive Subscripted Functions (Hashed Arrays) . . . . . . . . . . . . . . . . .
1.9.5 Recursive Hashed Arrays and Memoizing . . . . . . . . . . . . . . . . . . . . . . . .
1.9.6 Recursive Subscripted Maxima Functions . . . . . . . . . . . . . . . . . . . . . . . .
1.9.7 Floating Point Numbers from a Maxima Function . . . . . . . . . . . . . . . . . . . .
1.10 Pulling Out Overall Factors from an Expression . . . . . . . . . . . . . . . . . . . . . . . . .
1.11 Construction and Use of a Test Suite File . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.12 History of Maximas Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
4
4
9
11
16
18
20
21
21
22
24
25
25
26
28
30
33
34
35
37
42
44
46
46
47
47
50
50
51
52
53
53
55
56
57
This is a live document. This version uses Maxima 5.19.0. Check http://www.csulb.edu/woollett/ for the latest version of
these notes. Send comments and suggestions for improvements to [email protected]
Maxima by Example:
Ch. 2, Plots, Files, Read, Write, and Fit
Edwin L. Woollett
January 6, 2014
Contents
2.1
2.2
2.3
Introduction to plot2d . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.1 First Steps with plot2d . . . . . . . . . . . . . . . . . . . . . . . .
2.1.2 Parametric Plots . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.1.3 Can We Draw A Circle? . . . . . . . . . . . . . . . . . . . . . . .
2.1.4 Line Width and Color Controls . . . . . . . . . . . . . . . . . . . .
2.1.5 Discrete Data Plots: Point Size, Color, and Type Control . . . . . .
2.1.6 More gnuplot preamble Options . . . . . . . . . . . . . . . . . .
2.1.7 Creating Various Kinds of Graphics Files Using plot2d . . . . . . .
2.1.8 Using qplot for Quick Plots of One or More Functions . . . . . . .
2.1.9 Plot of a Discontinuous Function . . . . . . . . . . . . . . . . . . .
Working with Files Using the Package mfiles.mac . . . . . . . . . . . . . .
2.2.1 Check File Existence with file search or probe file . . . . . . . . .
2.2.2 Check for File Existence using ls or dir . . . . . . . . . . . . . . .
2.2.3 Type of File, Number of Lines, Number of Characters . . . . . . .
2.2.4 Print All or Some Lines of a File to the Console . . . . . . . . . . .
2.2.5 Rename a File using rename file . . . . . . . . . . . . . . . . . .
2.2.6 Delete a File with delete file . . . . . . . . . . . . . . . . . . . . .
2.2.7 Copy a File using copy file . . . . . . . . . . . . . . . . . . . . . .
2.2.8 Change the File Type using file convert . . . . . . . . . . . . . . .
2.2.9 Breaking File Lines with pbreak lines or pbreak() . . . . . . . . .
2.2.10 Search Text Lines for Strings with search file . . . . . . . . . . . .
2.2.11 Search for a Text String in Multiple Files with search mfiles . . . .
2.2.12 Replace Text in File with ftext replace . . . . . . . . . . . . . . .
2.2.13 Email Reply Format Using reply to . . . . . . . . . . . . . . . . .
2.2.14 Reading a Data File with read data . . . . . . . . . . . . . . . . .
2.2.15 File Lines to List of Strings using read text . . . . . . . . . . . . .
2.2.16 Writing Data to a Data File One Line at a Time Using with stdout .
2.2.17 Creating a Data File from a Nested List Using write data . . . . .
Least Squares Fit to Experimental Data . . . . . . . . . . . . . . . . . . .
2.3.1 Maxima and Least Squares Fits: lsquares estimates . . . . . . . .
2.3.2 Syntax of lsquares estimates . . . . . . . . . . . . . . . . . . . .
2.3.3 Coffee Cooling Model . . . . . . . . . . . . . . . . . . . . . . . .
2.3.4 Experiment Data for Coffee Cooling . . . . . . . . . . . . . . . .
2.3.5 Least Squares Fit of Coffee Cooling Data . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
5
6
9
11
15
16
17
19
19
19
20
21
21
22
22
22
22
23
25
26
28
29
29
31
31
32
33
33
34
35
36
38
Maxima by Example:
Ch. 3, Ordinary Differential Equation Tools
Edwin L. Woollett
September 16, 2010
Contents
3.1
3.2
3.3
3.4
3.5
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
3
3
5
6
7
9
9
9
12
16
17
19
19
22
23
24
28
30
31
32
33
33
37
43
This version uses Maxima 5.18.1 Check http://www.csulb.edu/woollett/ for the latest version of these notes. Send comments
and suggestions to [email protected]
Edwin L. Woollett
January 29, 2009
Contents
4
Solving Equations
4.1
4.2
4.3
4.1.1
4.1.2
4.1.3
4.1.4
4.1.5
4.1.6
4.1.7
4.1.8
Psuedo-PostFix Code: %% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.1.9
4.1.10
11
4.1.11
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
4.1.12
14
4.1.13
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
16
4.2.1
4.2.2
4.2.3
. . . . . . . . . . . . . . . . . . . . . . . . . .
21
4.2.4
23
4.2.5
newton
26
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
nd root
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . .
17
18
28
4.3.1
. . . . . . . . . . . . . . . . . .
28
4.3.2
29
4.3.3
. . . . . . . . . . . . . . . . . . . . . . .
30
4.3.4
31
4.3.5
32
4.3.6
34
4.3.7
35
4.3.8
. . . . . . . . . . . . . . . . . . . . .
37
4.3.9
37
4.3.10
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
38
4.3.11
Another Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
4.3.12
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
4.3.13
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
http://www.csulb.edu/woollett/
[email protected]
qdraw
Edwin L. Woollett
January 29, 2009
Contents
5
5.1
5.2
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
10
5.3
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12
5.4
14
5.5
. . . . . . . . . . . . . . . . . . . . . . . . . . .
17
5.6
19
5.7
21
5.8
. . . . . . . . . . . . . . . . . . . . . . . . . .
27
5.9
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
31
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
34
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
35
. . . . . . . . . . . . . . . . . . . . . . . . . .
38
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
43
5.17.1
5.17.2
47
5.17.3
. . . . . . . . . . . . . . .
48
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
49
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
5.19.1
General Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
50
5.19.2
XMaxima Tips
5.19.3
Suggested Projects
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
5.20 Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
http://www.csulb.edu/woollett/
[email protected]
Contents
6 Differential Calculus
6.1 Differentiation of Explicit Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.1 All About diff . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.2 The Total Differential . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.1.3 Controlling the Form of a Derivative with gradef . . . . . . . . . . . . . . . . . . . . . . . .
6.2 Critical and Inflection Points of a Curve Defined by an Explicit Function . . . . . . . . . . . . . . . .
6.2.1 Example 1: A Polynomial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2.2 Automating Derivative Plots with plotderiv . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2.3 Example 2: Another Polynomial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.2.4 Example 3: x2/3 , Singular Derivative, Use of limit . . . . . . . . . . . . . . . . . . . . .
6.3 Tangent and Normal of a Point of a Curve Defined by an Explicit Function . . . . . . . . . . . . . . .
6.3.1 Example 1: x2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.3.2 Example 2: ln(x) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.4 Maxima and Minima of a Function of Two Variables . . . . . . . . . . . . . . . . . . . . . . . . . .
6.4.1 Example 1: Minimize the Area of a Rectangular Box of Fixed Volume . . . . . . . . . . . . .
6.4.2 Example 2: Maximize the Cross Sectional Area of a Trough . . . . . . . . . . . . . . . . . .
6.5 Tangent and Normal of a Point of a Curve Defined by an Implicit Function . . . . . . . . . . . . . . .
6.5.1 Tangent of a Point of a Curve Defined by f (x, y) = 0 . . . . . . . . . . . . . . . . . . . . .
6.5.2 Example 1: Tangent and Normal of a Point of a Circle . . . . . . . . . . . . . . . . . . . . .
6.5.3 Example 2: Tangent and Normal of a Point of the Curve sin(2 x) cos(y) = 0.5 . . . . . .
6.5.4 Example 3: Tangent and Normal of a Point on a Parametric Curve: x = sin(t), y = sin(2 t)
6.5.5 Example 4: Tangent and Normal of a Point on a Polar Plot: x = r(t) cos(t), y = r(t) sin(t)
6.6 Limit Examples Using Maximas limit Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.6.1 Discontinuous Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.6.2 Indefinite Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.7 Taylor Series Expansions using taylor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.8 Vector Calculus Calculations and Derivations using vcalc.mac . . . . . . . . . . . . . . . . . . . . .
6.9 Maxima Derivation of Vector Calculus Formulas in Cylindrical Coordinates . . . . . . . . . . . . .
6.9.1 The Calculus Chain Rule in Maxima . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.9.2 Laplacian 2 f (, , z) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.9.3 Gradient f (, , z) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.9.4 Divergence B(, , z) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.9.5 Curl B(, , z) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6.10 Maxima Derivation of Vector Calculus Formulas in Spherical Polar Coordinates . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
4
4
5
6
7
7
9
11
12
13
14
14
15
16
18
19
21
23
25
26
27
28
29
32
34
36
40
41
43
45
48
49
50
This version uses Maxima 5.21.1 This is a live document. Check http://www.csulb.edu/woollett/ for the latest version of these
notes. Send comments and suggestions to [email protected]
Maxima by Example:
Ch.7: Symbolic Integration
Edwin L. Woollett
September 16, 2010
Contents
7.1
7.2
7.3
7.4
7.5
7.6
7.7
7.8
7.9
7.10
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
4
12
14
17
19
22
24
28
29
This version uses Maxima 5.18.1. This is a live document. Check http://www.csulb.edu/woollett/ for the
latest version of these notes. Send comments and suggestions to [email protected]
Maxima by Example:
Ch.8: Numerical Integration
Edwin L. Woollett
November 16, 2012
Contents
8.1
8.2
8.3
8.4
8.5
8.6
8.7
8.8
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Using nint and quad for One or Two Dimensional Quadrature . . . . . . . . . . . . .
8.2.1 Loading the nint Package . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8.2.2 nint and quad Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8.2.3 1D Quadrature Using mdefint and ndefint . . . . . . . . . . . . . . . . . . .
8.2.4 1D Quadrature Examples Using nint and quad . . . . . . . . . . . . . . . . .
8.2.5 2D Quadrature Examples Using nint and quad . . . . . . . . . . . . . . . . .
8.2.6 The nint Package Sets domain to complex: Caution! . . . . . . . . . . . . . .
8.2.7 Case: Symbolic Definite Integral the Difference of Two Almost Equal Numbers
8.2.8 Turning Off Automatic Chop of Answer . . . . . . . . . . . . . . . . . . . . .
8.2.9 Changing the Chop Value Used by nint . . . . . . . . . . . . . . . . . . . . .
Arbitrary Precision One Dimensional Quadrature with apnint and apquad . . . . . . .
Using the Wolfram Alpha Web Site for Integrals . . . . . . . . . . . . . . . . . . . . .
Direct Quadpack Use of quad qags, quad qag, and quad qagi . . . . . . . . . . . .
8.5.1 Syntax for Quadpack Functions . . . . . . . . . . . . . . . . . . . . . . . . .
8.5.2 Ouput List of Quadpack Functions and Error Code Values . . . . . . . . . . .
8.5.3 Integration Rule Parameters and Optional Arguments . . . . . . . . . . . . . .
8.5.4 quad qags for a Finite Interval . . . . . . . . . . . . . . . . . . . . . . . . .
8.5.5 quad qags for Double Integrals . . . . . . . . . . . . . . . . . . . . . . . . .
8.5.6 quad qag for a General Oscillatory Integrand . . . . . . . . . . . . . . . . .
8.5.7 quad qagi for a Non-finite Interval . . . . . . . . . . . . . . . . . . . . . . .
Numerical Integration: Sharper Tools . . . . . . . . . . . . . . . . . . . . . . . . . .
8.6.1 quad qagp for Internal Integrand Singularities . . . . . . . . . . . . . . . . .
8.6.2 quad qawo for Fourier Series Coefficients . . . . . . . . . . . . . . . . . . .
8.6.3 quad qaws for End Point Algebraic and Logarithmic Singularities . . . . . . .
8.6.4 quad qawc for a Cauchy Principal Value Integral . . . . . . . . . . . . . . . .
8.6.5 quad qawf for a Semi-Infinite Range Cosine or Sine Fourier Transform . . . .
Finite Region of Integration Decision Tree . . . . . . . . . . . . . . . . . . . . . . .
Non-Finite Region of Integration Decision Tree . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
3
4
6
7
9
10
11
12
12
13
16
17
17
18
18
19
22
23
26
28
28
28
29
31
33
34
35
This version uses Maxima 5.28.0. This is a live document. Check http://www.csulb.edu/woollett/ for the
latest version of these notes. Send comments and suggestions to [email protected]
Maxima by Example:
Ch.9: Bigfloats and Arbitrary Precision Quadrature
Edwin L. Woollett
February 3, 2011
Contents
9.1
9.2
9.3
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
The Use of Bigfloat Numbers in Maxima . . . . . . . . . . . . . .
9.2.1 Bigfloat Numbers Using bfloat, fpprec, and fpprintprec .
9.2.2 Using print and printf with Bigfloats . . . . . . . . . . . .
9.2.3 Adding Bigfloats Having Differing Precision . . . . . . . .
9.2.4 Polynomial Roots Using bfallroots . . . . . . . . . . . . .
9.2.5 Bigfloat Number Gaps and Binary Arithmetic . . . . . . . .
9.2.6 Effect of Floating Point Precision on Function Evaluation .
Arbitrary Precision Quadrature with Maxima . . . . . . . . . . . .
9.3.1 Using bromberg for Arbitrary Precision Quadrature . . . .
9.3.2 A Double Exponential Quadrature Method for a x <
9.3.3 The tanh-sinh Quadrature Method for a x b . . . . .
9.3.4 The Gauss-Legendre Quadrature Method for a x b .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
3
7
10
11
15
16
17
17
20
23
29
This version uses Maxima 5.18.1 except for the revised section on bfallroots, which uses Maxima 5.23.2. The author would like
to thank the Maxima developers for their friendly help via the Maxima mailing list, and Michel Talon for feedback about bfallroots
behavior.This is a live document. Check http://www.csulb.edu/woollett/ for the latest version of these notes. Send
comments and suggestions to [email protected]
Maxima by Example:
Ch.10: Fourier Series, Fourier and Laplace Transforms
Edwin L. Woollett
September 16, 2010
Contents
10.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2 Fourier Series Expansion of a Function . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2.1 Fourier Series Expansion of a Function over (, ) . . . . . . . . . . . . .
10.2.2 Fourier Series Expansion of f (x) = x over (, ) . . . . . . . . . . . . .
10.2.3 The calculus/fourie.mac Package: fourier, foursimp, fourexpand . . . . . .
10.2.4 Fourier Series Expansion of a Function Over (p, p) . . . . . . . . . . . . . .
10.2.5 Fourier Series Expansion of the Function |x| . . . . . . . . . . . . . . . . . .
10.2.6 Fourier Series Expansion of a Rectangular Pulse . . . . . . . . . . . . . . . .
10.2.7 Fourier Series Expansion of a Two Element Pulse . . . . . . . . . . . . . . . .
10.2.8 Exponential Form of a Fourier Series Expansion . . . . . . . . . . . . . . . .
10.3 Fourier Integral Transform Pairs . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.3.1 Fourier Cosine Integrals and fourintcos(..) . . . . . . . . . . . . . . . . . . .
10.3.2 Fourier Sine Integrals and fourintsin(..) . . . . . . . . . . . . . . . . . . . . .
10.3.3 Exponential Fourier Integrals and fourint . . . . . . . . . . . . . . . . . . . .
10.3.4 Example 1: Even Function . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.3.5 Example 2: Odd Function . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.3.6 Example 3: A Function Which is Neither Even nor Odd . . . . . . . . . . . .
10.3.7 Dirac Delta Function (x) . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.3.8 Laplace Transform of the Delta Function Using a Limit Method . . . . . . . .
10.4 Laplace Transform Integrals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.4.1 Laplace Transform Integrals: laplace(..), specint(..) . . . . . . . . . . . . . .
10.4.2 Comparison of laplace and specint . . . . . . . . . . . . . . . . . . . . . . .
10.4.3 Use of the Dirac Delta Function (Unit Impulse Function) delta with laplace(..)
10.5 The Inverse Laplace Transform and Residues at Poles . . . . . . . . . . . . . . . . .
10.5.1 ilt: Inverse Laplace Transform . . . . . . . . . . . . . . . . . . . . . . . . . .
10.5.2 residue: Residues at Poles . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
3
4
5
7
8
11
13
16
18
18
19
21
21
24
26
28
31
32
32
32
36
36
36
37
This version uses Maxima 5.18.1. This is a live document. Check http://www.csulb.edu/woollett/ for the
latest version of these notes. Send comments and suggestions to [email protected]
Maxima by Example:
Ch.11: Fast Fourier Transform Tools
Edwin L. Woollett
August 13, 2009
Contents
11.1 Examples of the Use of the Fast Fourier Transform Functions fft and inverse fft . . . . .
11.1.1 Example 1: FFT Spectrum of a Monochromatic Signal . . . . . . . . . . . . . .
11.1.2 Example 2: FFT Spectrum of a Sum of Two Monochromatic Signals . . . . . .
11.1.3 Example 3: FFT Spectrum of a Rectangular Wave . . . . . . . . . . . . . . . .
11.1.4 Example 4: FFT Spectrum Sidebands of a Tone Burst Before and After Filtering
11.1.5 Example 5: Cleaning a Noisy Signal using FFT Methods . . . . . . . . . . . . .
11.2 Our Notation for the Discrete Fourier Transform and its Inverse . . . . . . . . . . . . . .
11.3 Syntax of qfft.mac Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.4 The Discrete Fourier Transform Derived via a Numerical Integral Approximation . . . .
11.5 Fast Fourier Transform References . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
8
10
13
17
22
25
27
28
This is a live document. This version uses Maxima 5.19.0. Check http://www.csulb.edu/woollett/ for the latest version of
these notes. Send comments and suggestions for improvements to [email protected]
Maxima by Example:
Ch. 12, Dirac Algebra and Quantum Electrodynamics
Edwin L. Woollett
April 15, 2011
Contents
12.1 References . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.2 High Energy Physics Notation Conventions . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.2.1 Contraction and Trace Theorems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.3 Introduction to the Dirac Package, Version 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.4 Overview and Examples of the Dirac Package Tools . . . . . . . . . . . . . . . . . . . . . . .
12.4.1 Some Basic Package Symbols . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.4.2 Symbolic Expansions of D(a,b) using Dexpand . . . . . . . . . . . . . . . . . . . . . .
12.4.3 Some Examples of the Symbolic Expansion of G(a,b,c,...) Using Gexpand . . . . . . .
12.4.4 Symbolic and Explicit Matrix Trace Examples: tr, Gtr, mat trace, m tr . . . . . . . .
12.4.5 Symbolic and Explicit Matrix Contraction Examples Using Con . . . . . . . . . . . . .
12.4.6 Examples of noncov, comp def, VP, and econ . . . . . . . . . . . . . . . . . . . . . .
12.4.7 Contraction of a Product of Traces: Con, scon, mcon, econ . . . . . . . . . . . . . . .
12.4.8 Contraction Choices: Timing Comparisons for Polarized Squared Amplitudes . . . . . .
12.4.9 Dirac Spinors and Helicity Amplitudes . . . . . . . . . . . . . . . . . . . . . . . . . .
12.4.10 Polarized Amplitudes for (electron,positron) (muon, antimuon) . . . . . . . . . . . .
12.5 moller0.mac: Scattering of Identical Scalar (Spin 0) Charged Particles . . . . . . . . . . . . . .
12.6 moller1.mac: High Energy Elastic Scattering of Two Electrons . . . . . . . . . . . . . . . . . .
12.7 moller2.mac: Arbitrary Energy Moller Scattering . . . . . . . . . . . . . . . . . . . . . . . . .
12.8 bhabha1.mac: High Energy Limit of Bhabha Scattering . . . . . . . . . . . . . . . . . . . . . .
12.9 bhabha2.mac: Arbitrary Energy Bhabha Scattering . . . . . . . . . . . . . . . . . . . . . . . .
12.10 photon1.mac: Photon Transverse Polarization 3-Vector Sums . . . . . . . . . . . . . . . . . .
12.11 Covariant Physical External Photon Polarization 4-Vectors - A Review . . . . . . . . . . . . .
12.12 compton0.mac: Compton Scattering by a Spin 0 Structureless Charged Particle . . . . . . . . .
12.13 compton1.mac: Lepton-photon scattering . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.14 pair1.mac: Unpolarized Two Photon Pair Annihilation . . . . . . . . . . . . . . . . . . . . . .
12.15 pair2.mac: Polarized Two Photon Pair Annihilation Amplitudes . . . . . . . . . . . . . . . . .
12.16 moller3.mac: Squared Polarized Amplitudes Using Symbolic or Explicit Matrix Trace Methods
12.17 List of Dirac Package Files and Example Batch Files . . . . . . . . . . . . . . . . . . . . . .
12.18 Test Suite Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
12.19 Using simplifying-new.lisp . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
5
9
10
13
14
14
16
18
20
22
23
25
26
32
37
43
46
49
53
54
55
59
63
66
75
81
82
83
This version uses Maxima 5.23.2 Check http://www.csulb.edu/woollett/ for the latest version of these notes. Send comments
and suggestions to [email protected]
Acknowledgements
Some of the examples used in these notes are from the Maxima html help manual or the Maxima mailing list:
http://maxima.sourceforge.net/maximalist.html.
Our discussion begins with some of the nuts and bolts of using the software in a Windows XP environment, and continues with information useful to a new user.
The author would like to thank the Maxima developers for their friendly help via the Maxima mailing list.
There you can download tutorials in the form of zip files, which, when unzipped, become wxMaxima document format
(wxm) files which can then be loaded into your wxMaxima work session.
10minute.zip contains a ten minute wxMaxima tutorial. usingwxmaxima.zip provides general information
about the cell structure of wxMaxima.
5
Starting wxMaxima
One can use the Windows Start menu:
start, All Programs, Maxima-5.19.0, wxMaxima
During the Windows binary setup process you can select the options which place icons for both wxMaxima and XMaxima
on your desktop for a convenient start, and you can later copy any shortcut and paste it into your work folder for an
alternative start method.
Quitting wxMaxima
The quick way to quit is the two-key command Ctrl + q.
The Maxima Manual
To access the Maxima manual from within wxMaxima, you can use function key F1 or the menu item
Help, Maxima Help.
6
The next cell is an example of an input cell, which has the input prompt >> at the top. Note that we can include a text
comment within an input cell (which will be ignored by the Maxima computational engine) by putting the comment
between the delimiters /* and */ :
---| >> /* this is an input cell - it holds Maxima code and can be
| evaluated by first left-clicking once anywhere in the cell and
| then using the two-key command SHIFT-ENTER. The code entered in this cell
| will be sent to Maxima when you press SHIFT-ENTER. Before
| wxMaxima sends code to Maxima, it checks if the contents
| of each code command in this input cell ends with a ; or a $.
| If it doesnt, wxMaxima adds a ; at the end. Maxima requires that
| each completed Maxima statement end with either ; or $.
| Note that this does not mean you have to have each statement on
| one line. An input cell could have the contents
|
sin
|
(
|
x
|
);
|
| and this would be accepted as a complete Maxima input, equivalent to
|
sin(x);
|
| Any *output* wxMaxima gets from Maxima will be attached to the end of
| the input cell. Try clicking in this cell and pressing SHIFT-ENTER. */
|
|
/* example Maxmima code: */
|
|
print("Hello, world!")$
|
integrate(x2, x);
---
If you click once somewhere inside this cell the vertical left line changes to (if you have not changed the default) bright
red, indicating that the cell has been selected for some action. If you then press the two-key combination Shift + Enter,
the prompt >> will be replaced by (%i1), and the results of the two separate Maxima commands will be shown at the
bottom of the cell as:
| Hello, world!
|
3
|
x
|
(%o2) --|
3
----
except that the results are shown using pixel graphics with much better looking results than we show here.
There is no (%o1) since the print command was followed by the $ sign, which surpresses the normal default output.
If you have either a blank screen or a horizontal line present and just start typing, an input type cell is automatically
created. (You can instead, prior to typing, use the function key F7 to create a new input cell and can use the function key
F6 to create a new text cell).
In the current version of wxMaxima, if you change windows to some other task unrelated to wxMaxima, a junk input cell
may be created in wxMaxima containing something which looks like a percent sign >> % which you will see when you
come back to your wxMaxima window. If you want to have an input cell at that location, just backspace to get rid of the
weird symbol and continue.
7
If you then want to delete this junk cell, (or any cell you might be working on) just left-click on the bottom of the cell
bracket (which will highlight the bracket) and press the Delete key (or else select Edit, Cell, Cut Cell).
An alternative method is to use the horizontal line as a vertical position cursor which acts on cells. If your cursor is still
inside a cell you want to delete, use the DOWN key to get the cursor out of the cell, and the horizontal black line appears.
At that point you can press the backspace (or delete) key twice to delete the cell above the black horizontal line. Or you
can press SHIFT-UP once to select that cell and then press DELETE. Using SHIFT-UP more than once will select a group
of cells for action.
In the authors copy of wxMaxima (ie., using Windows XP), trying to use the usual Windows menu key combination
Alt + E, for example, does not actuate the wxMaxima Edit menu icon; one must left-click on that Edit icon at the top of
the screen to choose among the options.
The next cell is a text cell which does not need Maxima comment delimiters /*
and
*/.
---|
| Again, there is a triangle at the top of both text and
| input type cells which we dont show. An open triangle is the
| default, but if you click on the triangle, it will turn solid
| black and a) for a text cell, the text content is hidden, and
| b) for an input type cell, the Maxima ouput of the cell is hidden.
| Clicking that solid black triangle again will restore the hidden
| portions to view.
|
| Editing cells is easy. To modify the contents of a cell,
| click into it (ie., left-click anywhere in the cell once).
| A cursor should appear and the left cell bracket should turn red,
| (in default style mode) indicating that the cell is ready to be edited.
|
| The usual Windows methods can be used to select parts of a cell.
| One method is to hold the left mouse button down while you drag
| over your selection. A second method combines the SHIFT key with
| other keys to make the selection. For example, left-click at
| a starting location. Then use the two-key command SHIFT-END to
| select to the end of the line (say) or SHIFT-RIGHTARROW to
| select part of the line. You can then use CTRL-C to copy your
| selection to the clipboard. You can then left-click somewhere
| else and use CTRL-V to paste the clipboard contents at that location.
| (This is the usual behvior: if you experience lack of correct pasting,
| you can temporarily revert to the longer process of using the
| Edit, Copy, and Edit, Paste menu items to get wxMaxima in the
|
right spirit).
| The DOWN arrow key will step down one line at a time through the
| cell lines and then make a horizontal line under the cell. You can
| also simply left-click in the space between cells to create the
| active horizontal line, which you can think of as a sort of
| cursor for vertical position. With the horizontal line present,
| simply start typing to automatically create a new input type cell.
| Or press the function key F6 to create a new text type cell
| at that vertical location.
--
When youre satisfied with the document youve created, save it using the two-key Ctrl + s command or the File, Save
menu command. Note that the output parts of input cells will not be saved. When you load your document later, you can
evaluate all cells by using the Edit, Cell, Evaluate all cells menu command or the shortcut two-key command Ctrl + r.
If the shortcut two-key command doesnt work the first time, just repeat once and it should work. The present version of
8
wxMaxima is a little cranky still. This will evaluate all the cells in the order they were originally created.
Some common Maxima commands are available through the seven menu icons: Maxima, Equations, Algebra, Calculus,
Simplify, Plot and Numeric. All of the menu choices which end with ..... will open a dialog, to help you formulate
your desired command. The resulting command will be inserted at the current horizontal cursors position or below the
currently active cell. The chosen command will also be evaluated.
Configuring the Buttons and Fonts
The bottom button panel can be configured through Edit, Configure, Options Tab, Button Panel, Full or Basic, and
the font type and size can be configured through Edit, Configure, Style Tab, Default Font, Choose Font, Times New
Roman, Regular, 12 , for 12 pt generic roman for example. This is smaller than the startup default font, and may be too
small for some users, but will allow more information to be seen per screen.
The default text cell background color is a six variable custom green that is nice. In the following, the italic box is left
unchecked unless mentioned otherwise. To change a color, click the color bar once. The author combines the 12 pt roman
choice with input labels in bold red, Maxima input in blue bold, text cell in bold black, strings in black bold italic, Maxima
questions in blue bold, and all of the following in bold black: output labels, function names, variables, numbers, special
constants, greek constants.
When you want to save your choices, select the Save button, which will write a file style.ini to the folder in which wxMaxima was started.
(The author uses a shortcut to wxMaxima placed in his c:\work2 windows xp folder, since that folder is where the
author expects saved wxm and xml files to be saved. By starting with the contents of that folder in view, the author can
then simply click on the wxMaxima shortcut link to begin work with wxMaxima in that folder.)
The author chose the Full bottom button option (the default is Basic), which draws twenty buttons in two rows at the
bottom of the screen. The top row contains the Simplify, Simplify(r), Factor, Expand, Simplify(tr), Expand(tr),
Reduce(tr), Rectform, Sum..., Product... buttons.
The bottom row contains the Solve..., Solve ODE..., Diff..., Integrate..., Limit..., Series..., Subst..., Map..., Plot2D...,
Plot2D... buttons.
Note that if you have made a selection before you left-click a button panel command or a menu command, that selection
will be used as the main (or only) argument to the command. Selection of a previous output or part of an input will work
in a similar manner. The selected button function will act on the input cell contents or selection and immediately proceed
with evaluation unless there is an argument dialog which must be completed.
Multiple Maxima Requests in One Input Cell
Here is a calculation of the cross sectional area a and volume v of a right circular cylinder in terms of the cross section
radius r and the height h (ignoring units). We first create an input cell as described above, by just starting to type the
following lines, ending each line with the ENTER key to allow entry of the following line.
|--| >>
|
|
---
(r : 10, h : 100)$
a : %pi * r2;
v : a * h;
Note that we put two Maxima assignment statements on one line, using the syntax ( job 1, job 2 )$. Naturally, you can
put more than two statements between the beginning and ending parentheses. Thus far, the Maxima computational engine
has not been invoked. The left cell bracket will be bright red (in the default style), and you will have a blinking cursor in
the cell somewhere.
9
If you now use the two-key command SHIFT-ENTER, all Maxima commands will be carried out and the ouputs will
show up (in the same order as the inputs) at the bottom of that input cell, looking like
---| (%i1)
|
|
| (%o2)
| (%o3)
---
(r : 10, h : 100)$
a : %pi * r2;
v : a * h;
100*%pi
10000*%pi
with the horizontal (vertical location) line present underneath. The input prompt >> was replaced with the input number
(%i1). Output (%o1) was not printed to the screen because the first input ended with $.
[ a, v ], numer ;
With the cell bracket highlighted in red and the blinking cursor inside the cell, press SHIFT-ENTER to carry out the
operation, which returns the numerical value of the cross-sectional area a and the cylinder volume v as a list.
---| (%i4)
| (%o4)
[ a, v ], numer ;
[314.1592653589793,31415.92653589793]
(x+2)*(x-2)
When you type a leading parenthesis (, the trailing parenthesis ) also appears automatically. However, if you type
an ending parenthesis anyway, wxMaxima will not use it, but rather will properly end with one parenthesis. However,
you should pay attention to this feature at first so you understand how it works. Un-needed parentheses will result in a
Maxima error message.
Now press HOME and then SHIFT-END to select the whole expression, (x+2)*(x-2), then click on the Simplify button
at the bottom of the screen. Maxima will apply a default type of simplification using the function ratsimp, and the cell
contents evaluation will show
|(%i5) ratsimp((x+2)*(x-2));
|
2
|(%o5) x - 4
Thus the Simplify button uses ratsimp to simplify an expression. Instead of using the Simplify button, you could use
the menu selection: Simplify, Simplify Expression. The word simplify is being used here in a loose fashion, since
Maxima has no way of knowing what a particular user will consider a useful simplification.
A nice feature of wxMaxima is that you can left-click on a Maxima function name (in an input cell) like ratsimp and then
press the function key F1, and the Maxima manual will open up to the entry for that function.
10
Note that if you had started with the input cell contents
---| >> log( (x+2)*(x-2) ) + log(x)
---
and then highlighted just the (x+2)*(x-2) portion, followed by clicking on the Simplify button, you would get the same
input and output we see above. Thus Maxima will ignore the rest of the expression. On the other hand, if you highlighted
the whole expression and then clicked on Simplify, you would get
---| (%i5)
|
| (%o5)
---
ratsimp(log((x+2)*(x-2))+log(x));
2
log(x - 4) + log(x)
fullratsimp
According to the Maxima manual
fullratsimp repeatedly applies ratsimp followed by non-rational simplification to an expression until no
further change occurs, and returns the result. When non-rational expressions are involved, one call to ratsimp
followed as is usual by non-rational (general) simplification may not be sufficient to return a simplified
result. Sometimes, more than one such call may be necessary. fullratsimp makes this process convenient.
Here is the Maxima manual example for fullratsimp, making use of the Xmaxima interface.
(%i1) expr: (x(a/2) + 1)2*(x(a/2) - 1)2/(xa - 1);
(%o1)
a/2
2
a/2
2
(x
- 1) (x
+ 1)
----------------------a
x - 1
(%o2)
2 a
a
x
- 2 x + 1
--------------a
x - 1
(%o4)/R/
- 1
a/2 4
a/2 2
(x
) - 2 (x
) + 1
----------------------a
x - 1
We see that fullratsimp returned a completely simplified result. rat(expr) converts expr to a canonical rational expression (CRE) form by expanding and combining all terms over a common denominator and cancelling out the greatest
common divisor of the numerator and denominator, as well as converting floating point numbers to rational numbers
within a tolerance of ratepsilon (see the Manual for more information about rat).
11
or click on the desktop icon for Xmaxima. You can copy the desktop icon to the Clipboard and paste it into any work
folder for quick access.
If you are new to Maxima, go through the quick start tutorial in the bottom window of Xmaxima. You can either click on
the expression to have it evaluated, or you can enter the expression, followed by a semi-colon (;) in the upper window
and press enter to have Maxima carry out the operation. In the top Xmaxima window, note that the two key command
Alt+p will type in the previous entry, and you can keep entering Alt+p until you get the entry you want (to edit or simply
rerun).
Once you know what you are doing, you can close the bottom window of Xmaxima by using the Menu bar. On that menu
bar, choose Options, Toggle Browser Visibility. To use only keyboard commands to close the bottom window, use the
succession: Alt + e, RightArrow, Enter.
To quit Xmaxima, choose File, Exit on the menu bar (or Alt+f, x).
The second short introduction can be found on the Start,All Programs, Maxima 5.19.0, Introduction link. Written by
Cornell University (Dept. of Theoretical and Applied Mechanics) Professor Richard Rand
(http://tam.cornell.edu/), this is an excellent short introduction to many basic features of Maxima. The advice in
Rands introduction to exit Maxima by typing quit(); is relevant if you are using the command line maxima version,
aka maxima console.
One important thing to remember when using Xmaxima is to never press Enter (to execute code) with a space between
the semicolon (or the dollar sign) and the postion of the cursor. At least on the authors Windows XP machine, Xmaxima
will hang and refuse to issue the next input prompt, and you will have to click on File, Restart on the Xmaxima menu
bar to start a new session. This type of error can creep in easily if you are copying code you have previously saved to a
text file, and have an extra space in the file. If you then select, copy, and paste that code fragment into Xmaxima, with the
space at the end intact, you should carefully backspace to either the semicolon or the dollar sign before pressing Enter.
The safest path is to make sure your original text selection for copy does not include a space beyond the dollar sign.
The Maxima Help Manual
The most important continuous source of information about Maxima syntax and reserved words is the Maxima Manual,
which you should leave open in a separate window. To open a separate Maxima Manual window from inside the XMaxima interface, click on the XMaxima menu item: Help, Maxima Manual ( you can use the shortcut Alt+h to open the
Help menu).
Move around this reference manual via either Contents or Index. For example, left-click Index and start typing
integrate. By the time you have typed in inte, you are close to the integrate entry, and you can either continue to type the whole word, or use the down arrow key to select that entry. Then press the Enter key. On the right side
will be the Maxima Manual entry for integrate.
To scroll the Maxima Manual page, double-click on the page, and then use the PageDown and PageUp keys and the
UpArrow and DownArrow keys. To return to the index entry panel, left click that panel, and type diff, which will take
you to the section of the Maxima Manual which explains how to evaluate a derivative.
12
The Xmaxima Manual
If you look at the Xmaxima manual via Help, Xmaxima Manual (Web Browser) , your default browser will come up
with a somewhat out of date manual with the sections: 1. Command-line options, 2. Xmaxima Window, 3. Entering
commands, 4. Session control, 5. Openmath plots, 6. The browser, 7. Getting Help, and Concept Index.
The first section 1. Command-line options is not relevant for Windows XP Xmaxima.
Xmaxima Font Choices
In Sec 2, Xmaxima Window, you will find the statement:
You can also choose different types and sizes for the fonts, in the section Preferences of the Options menu;
those settings will be saved for future sessions.
The defaults are Times New Roman with size adjustment 3 for proportional fonts and Courier New with size adjustment
2 for fixed fonts. Using the menu with Options, Preferences, you can click on the typeface buttons to select a different
font type, and can click on the size number button to select another font size. You then should click the Apply and Quit
button.
Entering Your Expression
In Xmaxima, every input prompt, like (%i1), is waiting for an input which conforms to Maximas syntax expectations.
There is no such thing as a text cell, although you can include text comments anywhere as long as they are delimited
by the standard comment delimiters /*
and
*/, which only need to occur at the very beginning and end of the
comment, even if the comment extends over many lines.
Here is the beginning of Sec.3, Entering Commands, from the Xmaxima manual. We have replaced some irrelevant or
obsolete material with updated instructions.
Most commonly, you will enter Maxima commands in the last input line that appears on the text Window.
That text will be rendered in weak green. If you press Enter, without having written a command-termination
character (either ; or $) at the end, the text will remain green and you can continue to write a multi-line
command. When you type a command-end character and press the Enter key, the text will become light blue
and a response from Maxima should appear in light black. You can also use the UpArrow or DownArrow
keys to move to a new line without sending the input for Maxima evaluation yet. If you want to clear part
of the current input from the beginning to some point, position your cursor at that point (even if the region
thereby selected spans several lines) and then use Edit, Clear input or the two-key command Ctrl+u.
If you move the cursor over the (%i1) input label, or any other label or output text (in black), you will not
be able to type any text there; that feature will prevent you from trying to enter a command in the wrong
place, by mistake. If you really want to insert some additional text to modify Maximas output, and which
will not be interpreted by Maxima, you can do that using cut and paste (we will cover that later).
You can also write a new input command for Maxima on top of a previous input line (in blue), for instance,
if you do not want to write down again everything but just want to make a slight change. Once you press
the Enter key, the text you modified will appear at the last input line, as if you had written it down there;
the input line you modified will continue the same in Xmaximas and Maximas memory, in spite of having
changed in the screen.
13
For example, suppose you entered a: 45; in input line (%i1), and something else in (%i2).
(%i1) a:45;
(%o1)
(%i2) b:30;
(%o2)
45
30
You then move up over the (%i1) a: 45; and change the 5 to 8. You can then press End to get the cursor
at the end of the command, and then press Enter to submit the new (edited) command. At that point the
screen looks like:
(%i1) a:48;
(%o1)
(%i2) b:30;
(%o2)
(%i3) a:48;
(%o3)
45
30
48
But if you now enter (%i1); as input (%i4) and press Enter, the output (%o4) will be a: 45. The
screen will now look like:
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
a:48;
45
b:30;
30
a:48;
48
(%i1);
a : 45
Maxima knows the current binding of both (%i1) (which is the output (%o4)) and a
(%i5) a;
(%o5)
48
If you navigate through the input lines history (see next section), you will also see that the first input keeps
its original value.
Speeding up Your Work with XMaxima
When you want to edit your previous command, use Alt+p to enter the previous input (or use enough repetitions of Alt+p
to retrieve the command you want to start with). If the code extends over several screen lines, and/or your editing will
include deleting lines, etc., delete the command-completion character at the end (; or $) first, and then edit, and then
restore the command completion character to run the edited code.
The use of the keyboard keys Home, End, PageUp, PageDown, Ctrl+Home, and Ctrl+End (as well as UpArrow and
DownArrow greatly speeds up working with Xmaxima
For example to rerun as is or to copy a command which is located up near the top of your current Xmaxima session, first
use Home to put the cursor at the beginning of the current line, then PageUp or Ctrl+Home to get up to the top region
fast.
If you simply want to rerun that command as is, use End to get the cursor at the end of the entry (past the commandcompletion character), and simply press Enter to retry that command. The command will be evaluated with the state of
information Maxima has after the last input run. That entry will be automatically entered into your session (with new
output) at the bottom of your session screen. You can get back to the bottom using the Ctrl+End two-key command.
14
Alternatively, if you dont want the retry the exact same command, but something similar, then select the part of the code
you want to use as a starting point for editing and press Ctrl+c to copy your selection to the Windows Clipboard. To
select, you can either drag over the code with the mouse while you hold down the left mouse button, or else hold down
the Shift key with your left hand and and combine with the End, the LeftArrow, and the DownArrow keys to help you
select a region to copy.
Once you have selected and copied, press Ctrl+End to have the cursor move to the bottom of your workspace where
XMaxima is waiting for your next input and press Ctrl+v to paste your selection. If the selection extends over multiple
lines, use the down cursor key to find the end of the selection. If your selection included the command-completion character, remove it (backspace over that final symbol) before starting to edit your copied selection.
You are then in the drivers seat and can move around the code and make any changes without danger of Xmaxima preemptively sending your work to the Maxima engine until you finally have completed your editing, and move to the very
end and provide the proper ending (either ; or $) and then press Enter to evaluate the entry.
Using the Input Lines History
If your cursor is positioned next to the active input prompt at the bottom of the screen (ie., where Ctrl+End places the
cursor), you can use the key combinations Alt+p and Alt+n to recover the previous or next command that you entered.
For example, if you press Alt+n, you will enter the first input (%i1), and if you continue to press Alt+n, you will get in
sucession (%i2), (%i3),...
Alternatively, if the active input prompt is (%i10) and you press Alt+p repeatedly, you will get inputs (%i9), (%i8),
(%i7), ...
Searching for a String in Your Previous Inputs
Those same two-key combinations can also be used to search for a previous input lines containing a particular string.
Suppose you have one or more previous lines that included (among other functions) sin(something). At the last input
prompt, type sin and then use either of the two-key commands Alt+p or Alt+n repeatedly until the particular input line
containing the instance of sin you are looking for appears. You can then either immediately rerun that input line (press
End to get the cursor at the end of the input and then press Enter) or you can edit the input line using RightArrow and
LeftArrow, Home, and End to move around, and finally complete your editing and press Enter. In summary, you first
write down the string to search, and then Alt+p, to search backwards, or Alt+n to search forward. Pressing those key
combinations repeatedly will allow you to cycle through all the lines that contain the string. If you want to try a different
string in the middle of the search, you can delete the current input, type the new string, and start the search again.
Cutting and Pasting
You can cut or copy a piece of text that you select, from anywhere on the text window (ie., the main top window of
Xmaxima); not only from the input lines but also from the output text in black. To select the text, you can drag the cursor
with the mouse while you keep its left button depressed, or you can hold the Shift key with one finger, while you move
the cursor with the mouse or with the arrow keys.
Once you have selected the text, you can either cut it, with Edit, cut or the shortcut Ctrl+x, or copy it to an internal buffer
using Edit, copy or Ctrl+c. The text that has been cut or copied most recently can be pasted anywhere, even in the output
fields, using Edit, paste or Ctrl+v.
There is a command similar to cut, called kill, accessed via either Edit, kill or Ctrl+k, with two major differences: it
only works in input fields (blue or green) and instead of cutting a text that was selected, it will cut all the text from the
cursor until the end of the input line.
15
The command Edit, Clear input or Ctrl+u is similar to Edit, kill, but it will only work on the last input line (ie the
current input line) and will clear all from the beginning of that input line to the cursor position.
To paste the last text that you have cut with either kill or clear input, you should use the yank command Edit, yank
or Ctrl+y. If you use the Clear Input command, Ctrl+u, you can immediately restore the line with the yank command
Ctrl+y in a sort of UnDo.
Other Keyboard Shortcuts
Other useful key combinations are:
Ctrl+f, the same as RightArrow,
Ctrl+b, the same as LeftArrow,
Ctrl+p, the same as UpArrow,
Ctrl+n, the same as DownArrow,
Either Ctrl+a or Home moves to the left end of the current line (to the left of (%xn)),
Either Ctrl+e or End moves to the right end of the current line,
Ctrl+Home moves to the first character at the top of the text window,
Ctrl+End, moves to the last character at the bottom of the text window.
Save Xmaxima Session Record as a Text File
The menu command Edit, Save Console to File will bring up a dialog which allows you to select the folder and file name
with the default extension .out, and Xmaxima will save the current session screen, as it appears to you, to a text file with
that name. This can be a convenient way to keep a record of your work, particularly if you use the days date as part
of the name. You can then open that text file with any text editor, such as Notepad2, and edit it as usual, and you can
also change the name of the file. This session record is not in the form of inputs which you could use immediately with
Xmaxima, although you could copy and paste command inputs one at a time into a later Xmaxima session.
Save All Xmaxima Inputs as Lisp Code for Later Use in Maxima
The menu command File, Save Expressions to File will open a dialog which will save every input as Lisp code with a
file name like sat.bin or sat.sav. Although you can read such a file with a normal text editor, its main use to to rerun all
the inputs in a later session by using load(sat.bin), for example. All the variable assignments and function definitions
will be absorbed by Maxima, but you dont see any special output on the screen. Instead of that menu route, you could
just type the input save("C:/work2/sat1.bin",all); to create the Lisp code record of session inputs.
Save All Xmaxima Inputs in a Batch File Using stringout
If you type the input stringout("c:/work2/sat1.mac",input);, the inputs will be saved in the form of
Maxima syntax which can later be batched into a later Maxima session. In a later session, you type the input
batch("c:/work2/sat1.mac"); and on the screen will appear each input line as well as what each output is in
detail. (Or you could use the menu route File, Batch File, which will open a dialog which lets you select the file).
Quiet Batch Input
If you use the menu route File, Batch File Silently, you will not see the record of inputs and outputs in detail, but all the
bindings and definitions will be absorbed by Maxima. There will be no return value and no indication which file has been
loaded, so you might prefer typing load("c:/work2/sat1.mac");, or batchload("c:/work2/sat1.mac"); just
to have that record in your work.
16
Before we show the advantages of using your startup file, lets show what you need to do to load one of your *.mac files
in your work folder into Maxima without that startup file helping out. In my work folder c:/work2 is a file qfft.mac,
(available with Ch. 11 material on the authors web page) and here is an effort to load the file in Xmaxima.
(%i2) load(qfft);
Could not find qfft using paths in file_search_maxima,file_search_lisp.
-- an error. To debug this try debugmode(true);
(%i3) load("qfft.mac");
Could not find qfft.mac using paths in file_search_maxima,file_search_lisp.
-- an error. To debug this try debugmode(true);
(%i4) load("c:/work2/qfft.mac");
type qfft_syntax(); to see qfft and qift syntax
(%o4)
c:/work2/qfft.mac
On the other hand, if we have a link to ..bin/xmaxima.exe sitting in our work folder c:/work2 and we start Xmaxima
using that folder link we get
(%i2) load(qfft);
Could not find qfft using paths in file_search_maxima,file_search_lisp.
-- an error. To debug this try debugmode(true);
(%i3) load("qfft.mac");
type qfft_syntax(); to see qfft and qift syntax
(%o3)
qfft.mac
which shows one of the virtues of starting up Xmaxima using a link in your work folder.
Now that you know where Maxima is going to look for your startup file, make sure such a folder exists and create a file
named maxima-init.mac in that folder. You can have Maxima display a simple message when it reads your startup file
as an added check on what exactly is going on. For example, you could have the line disp (Hi, Cindy)$.
After saving the current version of that file in the correct folder, that message should appear after the Maxima version and
credits message.
Below is the authors startup file, in which he has chosen to tell Maxima to look in the c:/work2 folder for *.mac or
*.mc files, as well as the usual search paths. The chapter 1 utility file mbe1util.mac is loaded into the session.
/* this is c:\Documents and Settings\Edwin Woollett\maxima\maxima-init.mac */
/* last edit: 7-28-09 */
maxima_userdir: "c:/work2" $
maxima_tempdir : "c:/work2"$
file_search_maxima : append(["c:/work2/###.{mac,mc}"],file_search_maxima )$
file_search_lisp : append(["c:/work2/###.lisp"],file_search_lisp )$
load(mbe1util)$
print("
mbe1util.mac functions ", functions)$
disp("Maxima is the Future!")$
Naturally, you need to replace c:/work2 by the path to your own work folder.
17
With this startup file in place, here is the opening screen of Maxima, using the link to Xmaxima in my work folder to start
the session, and setting input (%i1) to be a request for the binding of maxima_userdir:
Maxima 5.19.0 http://maxima.sourceforge.net
Using Lisp GNU Common Lisp (GCL) GCL 2.6.8 (aka GCL)
Distributed under the GNU Public License. See the file COPYING.
Dedicated to the memory of William Schelter.
The function bug_report() provides bug reporting information.
mbe1util.mac functions [qplot(exprlist, prange, [hvrange]), rtt(e),
ts(e, v), to_atan(e, y, x), to_atan2(e, y, x), totan(e, v), totan2(e, v),
mstate(), mattrib(), mclean(), fll(x) ]
Maxima is the Future!
(%i1) maxima_userdir;
(%o1)
c:/work2
Now it is easy to load in the package qfft.mac, and see the large increase in the number of user defined functons.
(%i2) load(qfft)$
(%i3) functions;
(%o3) [qplot(exprlist, prange, [hvrange]), rtt(e), ts(e, v), to_atan(e, y, x),
to_atan2(e, y, x), totan(e, v), totan2(e, v), mstate(), mattrib(), mclean(),
fll(x), nyquist(ns, fs), sample(expr, var, ns, dvar), vf(flist, dvar),
current_small(), setsmall(val), _chop%(ex), fchop(expr), fchop1(expr, small),
_fabs%(e), kg(glist), spectrum1(glist, nlw, ymax),
spectrum(glist, nlw, ymax, [klim]), spectrum_eps(glist, nlw, ymax, fname,
[klim])]
We can use the utility function mclean() to remove those qfft functions.
(%i4) mclean();
----- clean start
(%o0)
(%i1) functions;
(%o1) [qplot(exprlist, prange, [hvrange]), rtt(e), ts(e, v), to_atan(e, y, x),
to_atan2(e, y, x), totan(e, v), totan2(e, v), mstate(), mattrib(), mclean(),
fll(x)]
If we had instead used kill ( all ) , the intial set of utilities loaded in from mbe1util.mac would have also vanished.
(%i2) kill(all);
(%o0)
(%i1) functions;
(%o1)
done
[]
Of course you could then use a separate load(mbe1util) command to get them back.
18
+ 3
2417851639229258349412352
2417851639229258349412352
4096
Since the operator has precedence over +, a + b c means a + (b c), rather than (a + b) c.
Operator
+
!
!!
Description
addition
subtraction
multiplication
division
negation
exponentiation
non-commutative multiplication
non-commutative exponentiation
factorial
double factorial
19
Constants in Maxima
The following table summarizes predefined constants.
Constant
%e
%i
%pi
%phi
%gamma
inf
minf
Description
Base of the natural logarithms (e)
The square root of (1) (i)
The transcendental constant
pi ()
The golden mean (1 + 5)/2
The Euler-Mascheroni constant
Real positive infinity ()
Real negative infinity ()
Reserved Words
There are a number of reserved words which, if used as variable or function names, might be confusing to both the user
and Maxima. Their use might cause a possibly cryptic syntax error. Here are some of the well known and less well
known but short reserved words Of course there are many other Maxima function names, global option variables, and
af
and
av
args
array
at
bc2
carg
cf
cint
col
cov
cv
del
diag
diff
do
else
elseif
erf
ev
exp
f90
fft
fib
fix
for
from
gcd
gd
get
go
hav
ic1
ic2
if
ift
ilt
in
ind
inf
inrt
integrate
is
li
limit
min
next
not
op
or
plog
psi
product
put
rat
rem
rk
some
step
sum
then
thru
und
unless
vers
while
zeta
20
An important fact is that Maxima is case sensitive, so you can avoid name conflicts by capitalizing the names of your user
defined Maxima functions. Your Solve will not conflict with Maximas solve. This is a dumb example, but illustrates the
principle:
(%i6) Solve(x):= x2;
2
(%o6)
(%i7) Solve(3);
(%o7)
Solve(x) := x
9
Of course, it takes more typing effort to use capitalized function names, which is why they are not popular among power
users.
(%o1)
The input line is typed in a one dimensional version and, if the input completion character is a semi-colon ; then Xmaxima displays
the expression in a text based two-dimensional notation. You can force one-dimensional output if you set display2d to false:
(%i2)
(%i3)
(%o3)
(%i4)
(%i5)
display2d:false$
%o1;
x/(x3+1)
display2d:true$
%o1;
(%o5)
x
-----3
x + 1
When you want to show a piece of code to the Maxima mailing list, it is recommended that you show the output in the one-dimensional
form since otherwise, in the received message, exponents can appear in a shifted position which may be hard to interpret.
The output (%o6) is a symbolic expression which can be manipulated as a data structure. For example, you can add it to itself. The
Maxima symbol % refers to the last output line.
(%i6) % + %;
(%o6)
2 x
-----3
x + 1
Notice the automatic simplification carried out by default. Maxima could have left the result as a sum of two terms, but instead
recognised that the summands were identical and added them together producing a one term result. Maxima will automatically (in
default behavior) perform many such simplifications.
Here is an example of automatic simplification of a trig function:
(%i7) sin(x - %pi/2);
(%o7)
- cos(x)
21
Function describe
describe(e), describe(e, exact), describe(e, inexact)
describe(e) is equivalent to describe(e, exact) and prints to the screen the manual documentation of e.
describe(e, inexact) prints to the screen a numbered list of all items documented in the manual which contain e as part
of their name. If there is more than one list element, Maxima asks the user to select an element or elements to display.
SHORTCUTS:
At the interactive prompt, ? foo (with a space between ? and foo) and NO ENDING SEMICOLON (just press Enter)
is equivalent to either describe(foo) or describe(foo, exact), and ?? foo (with a space between ?? and foo) and NO
ENDING SEMICOLON (just press Enter) is equivalent to describe(foo, inexact).
In the latter case, the user will be asked to type either a set of space separated numbers to select some of the list elements,
such as 2 3 5 followed by Enter, or the word all followed by Enter, or the word none followed by Enter.
Here is an example of interactive use of the single question mark shortcut.
(%i2) ? exp
-- Function: exp (<x>)
Represents the exponential function. Instances of exp (<x>) in
input are simplified to %e<x>; exp does not appear in
simplified expressions.
demoivre if true causes %e(a + b %i) to simplify to %e(a
(cos(b) + %i sin(b))) if b is free of %i. See demoivre.
%emode, when true, causes %e(%pi %i x) to be simplified.
See %emode.
%enumer, when true causes %e to be replaced by 2.718...
whenever numer is true. See %enumer.
22
true
One option has the form V : e, or V = e, which causes V to be bound to the value of e during the evaluation of expr.
If more than one argument to ev is of this type, then the binding is done in parallel, as shown in the following example.
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
x+y, x
a+y;
2 y + a
%, y = 2;
a + 4
x+y, x = a+y, y = 2;
y + a + 2
x+y, [x = a+y, y = 2];
y + a + 2
23
Our final example shows the use of rectform and ratsimp to make explicit the fourth roots of 1 returned by solve.
(%i1) solve ( a4 + 1 );
1/4
1/4
1/4
1/4
(%o1) [a = (- 1)
%i, a = - (- 1)
, a = - (- 1)
%i, a = (- 1)
]
(%i2) % , rectform, ratsimp;
sqrt(2) %i - sqrt(2)
sqrt(2) %i + sqrt(2)
(%o2) [a = --------------------, a = - --------------------,
2
2
sqrt(2) %i - sqrt(2)
sqrt(2) %i + sqrt(2)
a = - --------------------, a = --------------------]
2
2
(%i3) %4, ratsimp;
4
4
4
4
(%o3)
[a = - 1, a = - 1, a = - 1, a = - 1]
Both rectform and ratsimp are Maxima functions which have the property evfun (see next entry), which means that
ev(expr, rectform, ratsimp) is equivalent to ratsimp ( rectform ( ev(expr) ) ) .
Property evflag
When a symbol x has the evflag property, the expressions ev(expr, x) and expr, x (at the interactive prompt) are
equivalent to ev(expr, x = true). That is, x is bound to true while expr is evaluated.
The expression declare(x, evflag) gives the evflag property to the variable x.
The flags which have the evflag property by default are the following:
algebraic, cauchysum, demoivre, dotscrules, %emode, %enumer, exponentialize,
exptisolate, factorflag, float, halfangles, infeval, isolate_wrt_times,
keepfloat, letrat, listarith, logabs, logarc, logexpand, lognegint, lognumer,
m1pbranch, numer_pbranch, programmode, radexpand, ratalgdenom, ratfac,
ratmx, ratsimpexpons, simp, simpsum, sumexpand, and trigexpand.
Even though the Boolean switch numer does not have the property evflag, it can be used as if it does.
(%i4) [exponentialize,float,numer,simp];
(%o4)
[false, false, false, true]
(%i5) properties(exponentialize);
(%o5) [system value, transfun, transfun, transfun, transfun, transfun,
transfun, evflag]
(%i6) properties(numer);
(%o6)
[system value, assign property]
(%i7) properties(float);
(%o7) [system value, transfun, transfun, transfun, transfun, transfun,
evflag, transfun, transfun]
(%i8) properties(simp);
(%o8)
[system value, evflag]
(For the use of the key word expand in this context, see below.)
24
Property evfun
When a Maxima function F has the evfun property, the expressions ev(expr, F) and expr, F (at the interactive
prompt) are equivalent to F ( ev (expr)).
If two or more evfun functions F, G, etc., are specified, then ev ( expr, F, G ) is equivalent to G ( F ( ev(expr) ) ).
The command declare(F, evfun) gives the evfun property to the function F.
The functions which have the evfun property by default are the following very useful and single argument funtions: bfloat,
factor, fullratsimp, logcontract, polarform, radcan, ratexpand, ratsimp, rectform, rootscontract, trigexpand, and
trigreduce.
Note that rat, and trigsimp do not, by default, have the property evfun.
Some of the other key words which can be used with ev are expand, nouns, diff, integrate (even though they are not
obviously boolean switches and do not have the property evflag).
(%i12)
(%o12)
(%i13)
(%o13)
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
[diff,expand,integrate,nouns];
[diff, expand, integrate, nouns]
properties(expand);
[transfun, transfun, transfun, transfun, transfun]
(a+b)*(c+d);
(b + a) (d + c)
(a+b)*(c+d),expand;
b d + a d + b c + a c
ev((a+b)*(c+d),expand);
b d + a d + b c + a c
The undocumented property transfun apparently has something to do with translation to Lisp.
1.8.3 The List functions and the Function fundef
functions
functions is the name of a list maintained by Maxima and this list is printed to the screen (as would any list) with the
names of the current available non-core Maxima functions (either user defined interactively or defined by any packages
loaded into the current session). Here is the example we saw previously based on the authors startup file:
(%i1) functions;
(%o1) [qplot(exprlist, prange, [hvrange]), rtt(e), ts(e, v), to_atan(e, y, x),
to_atan2(e, y, x), totan(e, v), totan2(e, v), mstate(), mattrib(), mclean(),
fll(x)]
fundef
fundef(name) prints out the definition of a non-core Maxima function (if currently known by Maxima). Here is an
example related to the previous example which said that Maxima knew about a function called rtt.
(%i2) fundef(rtt);
(%o2)
rtt(e) := radcan(trigrat(trigsimp(e)))
(%i3) fundef(cos);
cos is not the name of a user function.
-- an error. To debug this try debugmode(true);
25
1.8.4 The Function kill and the List values
kill
kill(a,b) will eliminate the objects a and b. Special cases are kill(all) and kill(allbut(x,y)). Here is an example which
removes our user defined Maxima function rtt.
(%i1) kill(rtt);
(%o1)
done
(%i2) functions;
(%o2) [qplot(exprlist, prange, [hvrange]), ts(e, v), to_atan(e, y, x),
to_atan2(e, y, x), totan(e, v), totan2(e, v), mstate(), mattrib(), mclean(),
fll(x)]
values
values is another list maintained by Maxima which contains the names of currently assigned scalar values which have
been set by the user interactively or by packages which have been loaded. Here is a simple example.
(%i3) [ a:2, b:5, e: x2/3 ];
2
x
[2, 5, --]
3
(%o3)
(%i4) values;
(%o4)
[a, b, e]
The use of map with the Maxima function ratsimp allows a separate simplification to be carried out on each term of the
following expression.
(%i5) e : x/(x2+x)+(y2+y)/y ;
(%o5)
2
y + y
x
------ + -----y
2
x + x
(%i6) e, ratsimp;
(%o6)
(x + 1) y + x + 2
----------------x + 1
(%i7) map(ratsimp,e);
(%o7)
1
y + ----- + 1
x + 1
26
We create a list of equations from two lists using map.
(%i8) map( "=", [x,y,z],[a,b,c] );
(%o8)
[x = a, y = b, z = c]
2 %pi + 3 %e
- 4
f(2 %pi) + f(3 %e
)
(%o10)
(%i11) fullmap(f, expr);
f(- 4)
f(2) f(%pi) + f(3) f(%e)
(%o11)
apply
The Maxima function apply can be used with a list only (not an expression).
(%i12)
(%o12)
(%i13)
(%o13)
(%i14)
(%i15)
apply(f, [x,y,z]);
f(x, y, z)
apply("+",[x,y,z]);
z + y + x
dataL : [ [1,2], [2,4] ]$
dataM : apply(matrix, dataL );
[ 1 2 ]
(%o15)
[
]
[ 2 4 ]
(%i16) grind(%)$
matrix([1,2],[2,4])$
The function grind allows one dimensional display suitable for copying into another input line. The last example above
created a Maxima matrix object from a nested list. Maxima has many tools to work with matrix objects. To achieve one
dimensional display of such matrix objects (saving space), you can use display2d:false. To go from a Maxima
matrix object to a nested list, use args.
(%i17) args(dataM);
(%o17)
27
Some examples:
(%i1) e : f*x3 + g*cos(x);
3
(%o1)
(%i2) subst ( x = a, e );
g cos(x) + f x
3
(%o2)
cos(a) g + a
(%i3) e1 : subst ( x = a + b, e );
f
3
(%o3)
cos(b + a) g + (b + a)
(%i4) e2 : subst ( a + b = y, e1 );
3
(%o4)
g cos(y) + f y
(%i5) e3 : f*x3 + g*cos(y);
3
(%o5)
g cos(y) + f x
(%i6) e4 : subst ( [x = a+b, y = c+d],e3 );
3
(%o6)
cos(d + c) g + (b + a)
(%i7) subst ([a+b = r, c+d = p],e4 );
3
(%o7)
f r + g cos(p)
ratsubst
(%i8) e : a*f(y) + b*g(x);
(%o8)
a f(y) + b g(x)
(%i9) e1 : ratsubst( cos(y),f(y),e );
(%o9)
a cos(y) + b g(x)
(%i10) e2 : ratsubst( x3*sin(x),g(x),e1 );
3
(%o10)
a cos(y) + b x sin(x)
28
(%i19) substpart(sin,e,1,3,0);
(%o19)
(%i20)
(%o20)
(%i21)
(%o21)
(%i22)
(%o22)
- f(y)
a %e
sin(f(y))
-------------------b
length( part(e,1,3,1) );
1
[part(e,1,3,1,0), part(e,1,3,1,1)];
[f, y]
substpart(x,e,1,3,1,1);
- f(y)
a log(f(x)) %e
-------------------b
By judicious use of part and substpart, we see that we can modify a given expression in all possible ways.
1.8.7 Examples of coeff, ratcoef, and collectterms
collectterms
Use the syntax
collectterms ( expr, arg1, arg2, ...)
This Maxima function is best explained with an example. Consider the expression:
(%i1) ex1 :
(%o1)
How can we return this expanded expression to the original form? We first use collectterms, and then factor with map.
(%i2) collectterms(ex1,a1,a2);
3
2
2
e
d e
2
3
c
2
(%o2)
a2 (-- + ---- + d e + d ) + a1 (-- + b c + b )
27
3
4
(%i3) map(factor, %);
3
2
a2 (e + 3 d)
a1 (c + 2 b)
(%o3)
------------- + ------------27
4
Maximas core simplification rules prevent us from getting the 33 = 27 into the numerator of the first term, and also
from getting the 22 = 4 into the numerator of the second term, unless we are willing to do a lot of substpart piecework
(usually not worth the trouble).
coeff
The syntax
coeff ( expr, x, 3 )
will return the coefficient of x3 in expr.
29
The syntax
coeff ( expr, x )
will return the coefficient of x in expr.
x may be an atom or a complete subexpression of expr, such as sin(y), a[j], or (a+b). Sometimes it may be
necessary to expand or factor expr in order to make xn explicit. This preparation is not done automatically by coeff.
(%i4) coeff(%, a2);
(%o4)
3
(e + 3 d)
---------27
1
-27
(a x + b)
0
2 a b
2 a b
2
b
2
b
Both coeff and ratcoef can be used with equations (as well as expressions).
(%i12) eqn : (a*sin(x) + b*cos(x))3 = c*sin(x)*cos(x);
3
(%o12)
(a sin(x) + b cos(x)) = c cos(x) sin(x)
(%i13) ratcoef(eqn,sin(x),0);
3
3
(%o13)
b cos (x) = 0
(%i14) ratcoef(eqn,sin(x));
2
2
(%o14)
3 a b cos (x) = c cos(x)
30
1.8.8 Examples of rat, diff, ratdiff, ratexpand, expand, factor, gfactor and partfrac
Maxima provides tools which allow the user to write an expression in multiple forms. Consider the tenth order polynomial
in x given by
(%i1) e:(x + 3)10;
10
(%o1)
(x + 3)
We can use diff ( expr, x ) to find the first derivative of expr, and diff ( expr, x, 2 ) to find the second derivative of expr,
and so on.
(%i2) de1 : diff ( e, x );
9
(%o2)
10 (x + 3)
If you want the lowest powers displayed first, you have to change the setting of powerdisp to true.
(%i9) powerdisp;
(%o9)
(%i10) powerdisp : true$
(%i11) %o7;
false
2
(%o11) 59049 + 196830 x + 295245 x
3
4
5
+ 262440 x + 153090 x + 61236 x
6
7
8
9
10
+ 17010 x + 3240 x + 405 x + 30 x + x
31
Next we consider a sum of rational expressions:
(%i13) expr: (x - 1)/(x + 1)2 + 1/(x - 1);
x - 1
1
(%o13)
-------- + ----2
x - 1
(x + 1)
(%i14) expand ( expr );
x
1
1
(%o14)
------------ - ------------ + ----2
2
x - 1
x + 2 x + 1
x + 2 x + 1
(%i15) ratexpand ( expr );
2
2 x
2
(%o15)
--------------- + --------------3
2
3
2
x + x - x - 1
x + x - x - 1
We see that ratexpand wrote all fractions with a common denominator, whereas expand did not. In general, rat and
ratexpand is more efficient at expanding rational expressions. Here is a very large expression with many %pis which
can be simplified easily by the rat tribe, but expand takes a very long time and returns a mess.
(%i16) e :
((2/%pi-1)*(((%pi/2-1)/(%pi-1)-1)*((6*(2/%pi-2*(4-%pi)/%pi)/%pi-(6*(2*(4-%pi)
/%pi-(%pi-2)/(%pi/2-1))/(%pi-1)-6*((%pi-2)/(%pi/2-1)-2)*(%pi/2-1)
/(%pi*(%pi-1)))/(2*((2/%pi-1)*(%pi/2-1)/(2*(%pi-1)) +2)))
/(((%pi/2-1)/(%pi-1)-1)/(2*((2/%pi-1)*(%pi/2-1)/(2*(%pi-1))+2))+2)
-(6*(2*(2*%pi-5)/%pi-2/%pi)/%pi-(6*(2/%pi-2*(4-%pi)/%pi)/%pi
-(6*(2*(4-%pi)/%pi-(%pi-2)/(%pi/2-1))/(%pi-1)-6*((%pi-2)/(%pi/2-1)-2)
*(%pi/2-1)/(%pi*(%pi-1)))/(2*((2/%pi-1)*(%pi/2-1)/(2*(%pi-1))+2)))
/(2*(((%pi/2-1)/(%pi-1)-1)/(2*((2/%pi-1)*(%pi/2-1)/(2*(%pi-1))+2))+2)))
/(2*(2-1/(4*(((%pi/2-1)/(%pi-1)-1)/(2*((2/%pi-1)*(%pi/2-1)/(2*(%pi-1))+2))
+2)))*(((%pi/2-1)/(%pi-1)-1)/(2*((2/%pi-1)*(%pi/2-1)/(2*(%pi-1))
+2))+2)))/((2/%pi-1)*(%pi/2-1)/(2*(%pi-1))+2)+(6*(2*(4-%pi)/%pi-(%pi-2)
/(%pi/2-1))/(%pi-1)-6*((%pi-2)/(%pi/2-1)-2)*(%pi/2-1)/(%pi*(%pi-1)))
/((2/%pi-1)*(%pi/2-1)/(2*(%pi-1))+2))/2+6*((%pi-2)/(%pi/2-1)-2)/%pi)
*(x3-x)/6 + 2*x$
(%i17) ratsimp (e);
2
3
3
2
(128 %pi - 520 %pi + 528) x + (194 %pi - 248 %pi + 400 %pi - 528) x
(%o17) ----------------------------------------------------------------------3
2
97 %pi - 60 %pi - 60 %pi
(%i18) rat (e);
(%o18)/R/
2
3
3
2
(128 %pi - 520 %pi + 528) x + (194 %pi - 248 %pi + 400 %pi - 528) x
----------------------------------------------------------------------3
2
97 %pi - 60 %pi - 60 %pi
32
There is a more general form expand (expr, p, n) available to control which parts of fractions are expanded and how (see
the Manual index entry for expand). There is also a more general form for rat (expr, x_1, ..., x_n).
gfactor
The g in gfactor comes from factorization over the Gaussian integers.
(%i20) gfactor ( x2 + 1 );
(%o20)
(x - %i) (x + %i)
partfrac
We have earlier emphasized the usefulness of ratsimp. A Maxima function which in some cases can be considered
the opposite of ratsimp in its results is partfrac, which has the syntax partfrac ( expr, var ), and which
expands expr in partial fractions with respect to var. Here is the example presented in the Manual.
(%i21) e : 1/(1+x)2 - 2/(1+x) + 2/(2+x);
2
2
1
(%o21)
----- - ----- + -------x + 2
x + 1
2
(x + 1)
(%i22) e, ratsimp;
x
(%o22)
- ------------------3
2
x + 4 x + 5 x + 2
(%i23) partfrac (%, x);
2
2
1
(%o23)
----- - ----- + -------x + 2
x + 1
2
(x + 1)
33
1.8.9 Examples of integrate, assume, facts, and forget
An important symbolic tool is indefinite integration, much of which is performed algorithmically. The original integration
package, written by Joel Moses, incorporates the non-algebraic case of the Risch integration algorithm, and the package
is called sin.lisp ( sin is a mnemonic from Symbolic INtegrator ).
Consider the indefinite integral of a rational expression:
(%i1) e : x/(x3 + 1);
x
-----3
x + 1
(%o1)
(%o2)
2
2 x - 1
1
------------------ + -------------- - --------2
2
3 (x + 1)
(2 x - 1)
6 (x - x + 1)
3 (---------- + 1)
3
This answer, as it stands, is not identical to the starting integrand. The reason is that Maxima merely differentiates term
by term. Maxima automatically applies only those simplification rules which are considered obvious and always desirable. A particular simplification rule might make one expression smaller but might make another expression larger. In
such cases, Maxima leaves the decision to the user.
In this example, the starting integrand can be recovered by rational simplification using the ratsimp function.
(%i4) %, ratsimp;
(%o4)
x
-----3
x + 1
We met ratsimp and fullratsimp (Sec. 1.3.1) in our brief discussion of the buttons and menu system of wxMaxima,
where the Simplify button made use of ratsimp, a reflection of the frequent use you will make of this function. You can
think of the word ratsimp being a mnenomic using the capitalised letters in RATional SIMPlification.
If you try to use ratdiff on the above indefinite integration result, you get an obscure error message:
(%i5) ratdiff (ie, x);
ratdiff variable is embedded in kernel
-- an error. To debug this try debugmode(true);
The error message is returned because ratdiff (expr, x) can only be used for expressions which are either a polynomial in
x or a ratio of polynomials in x.
34
integrate consults the assume database when making algebraic decisions. The content of that database is returned by
facts();. You can sometimes avoid questions from integrate if you first provide some assumptions with assume.
Here is an example of a definite integral in which we start with no assumptions, and need to answer a question from
integrate.
(%i1) facts();
(%o1)
[]
(%i2) integrate(x*exp(-a*x)*cos(w*x),x,0,inf);
Is a positive, negative, or zero?
p;
(%o2)
2
2
w - a
- ----------------4
2 2
4
w + 2 a w + a
We can now tell Maxima that the parameter a should be treated as a positive number. We thereby avoid the question.
(%i3) ( assume(a > 0), facts() );
(%o3)
[a > 0]
(%i4) integrate(x*exp(-a*x)*cos(w*x),x,0,inf);
2
2
w - a
(%o4)
- ----------------4
2 2
4
w + 2 a w + a
[]
1.8.10 Numerical Integration and Evaluation: float, bfloat, and quad qags
Lets try a harder integral, this time a definite integral which is expressed by Maxima in terms of a special function.
(%i1) is : integrate( exp(x3),x,1,2 );
1
1
(sqrt(3) %i - 1) (gamma_incomplete(-, - 8) - gamma_incomplete(-, - 1))
3
3
(%o1) ---------------------------------------------------------------------6
(%i2) float(is);
(%o2) 0.16666666666667 (- 719.2849028287006 %i
- 1.0 (0.66608190774162 - 3.486369946257051 %i) - 412.6003937374765)
(1.732050807568877 %i - 1.0)
(%i3) expand(%);
(%o3)
275.5109837634787
(%i4) ival:%;
(%o4)
275.5109837634787
You can look up the gamma_incomplete(a,z) definition in the Maxima manual, where you will find a reference to
the incomplete upper gamma function A&S 6.5.2, which refers to Eq. 6.5.2 in Handbook of Mathematical Functions,
Edited by Milton Abramowitz and Irene A. Stegun, Dover Publications, N.Y., 1965.
We know that since we are integrating along the real x axis from 1 to 2, our integrand in (%i1) is real, so that the
numerical value of this integral must be a real number. In using float, we see that the real answer will be obtained by
cancellation of imaginary pieces, so we may have some roundoff errors.
35
Lets check the accuracy of using float here by comparing that answer to the answer returned by the use of bfloat together
with fpprec set to 20.
(%i5) bfloat(is),fpprec:20;
(%o5) 1.6666666666666666667b-1 (1.7320508075688772935b0 %i - 1.0b0)
(- 1.0b0 (6.6608190774161802181b-1 - 3.4863699462570511861b0 %i)
- 7.1928490282826659929b2 %i - 4.1260039373722578387b2)
(%i6) expand(%),fpprec:20;
(%o6)
5.7824115865893569814b-19 %i + 2.7551098376331160126b2
(%i7) tval20: realpart(%);
(%o7)
2.7551098376331160126b2
(%i8) abs(ival - tval20);
(%o8)
1.670912297413452b-10
We see that the numerical answer found using float only has twelve digit accuracy. Lets look at the numerical values of
the gamma_incomplete functions involved here as returned by float:
(%i9) float(gamma_incomplete(1/3,-8));
(%o9)
- 719.2849028287006 %i - 412.6003937374765
(%i10) float(gamma_incomplete(1/3,-1));
(%o10)
0.66608190774162 - 3.486369946257051 %i
Finally, lets use a pure numerical integration routine , quad_qags, which returns a list consisting of
[answer, est-error, num-integrand-eval, error-code].
(%i11) quad_qags(exp(x3),x,1,2);
(%o11)
[275.5109837633116, 3.2305615936931465E-7, 21, 0]
(%i12) abs(first(%) - tval20);
(%o12)
2.842170943040401b-14
and we see that the use of quad_qags for a numerical value was more accurate than the comination of integrate and
float.
1.8.11 Taylor and Laurent Series Expansions with taylor
When computing exact symbolic answers is intractable, one can often resort to series approximations to get approximate symbolic results. Maxima has an excellent Taylor series program. As an example, we can get truncated series
representations for sin(x) and cos(x) as follows. According to the Maxima manual
taylor (expr, x, a, n) expands the expression expr in a truncated Taylor or Laurent series in the variable x
around the point x = a, containing terms through (x a)n .
Here we expand around the point x = 0.
(%i1) taylor( sin(x),x,0,5 );
(%o1)/T/
3
5
x
x
x - -- + --- + . . .
6
120
(%o2)/T/
2
4
x
x
1 - -- + -- + . . .
2
24
A truncated series in denoted by the /T/ symbol next to the line label and also by the trailing dots. Maxima retains
certain information about such expansions, such as the quality of the approximation, so when several series expansions
are combined, no terms are computed beyond the degree of the approximation. In our example, our starting expansions
are only good through terms of order x5 , so if we multiply the expansions, any terms smaller (in order of magnitude) than
36
x5 are neglected.
Here we use %th(n), which refers to the nth to last line.
(%i3) % * %th(2);
(%o3)/T/
3
5
2 x
2 x
x - ---- + ---- + . . .
3
15
The name taylor is only an artifact of history, since the Maxima function taylor can handle expansions of functions
with poles and branch points and automatically generates Laurent series when appropriate as shown here:
(%i4) taylor( 1/ (cos(x) - sec(x))3, x,0,5 );
(%o4)/T/
2
4
1
1
11
347
6767 x
15377 x
- -- + ---- + ------ - ----- - ------- - -------- + . . .
6
4
2
15120
604800
7983360
x
2 x
120 x
37
1.8.12 Solving Equations: solve, allroots, realroots, and find root
The solve function is described in the Maxima manual
Function: solve (expr, x)
Function: solve (expr)
Function: solve ([eqn_1, ..., eqn_n], [x_1, ..., x_n])
Solves the algebraic equation expr for the variable x and returns a list of solution equations for x. If expr
is not an equation, the equation expr = 0 is assumed in its place. x may be a function (e.g. f(x)), or other
non-atomic expression except a sum or product. x may be omitted if expr contains only one variable. expr
may be a rational expression, and may contain trigonometric functions, exponentials, etc.
Example 1
Here we look for solutions of the equation x6 = 1 or x6 1 = 0. Once we have found candidate solutions, we check
them one at a time.
(%i1) eqn : x6 - 1 = 0$
(%i2) solns : solve(eqn);
sqrt(3) %i + 1
sqrt(3) %i - 1
sqrt(3) %i + 1
(%o2) [x = --------------, x = --------------, x = - 1, x = - --------------,
2
2
2
sqrt(3) %i - 1
x = - --------------, x = 1]
2
(%i3) for i thru length(solns) do
disp ( ev( eqn, solns[i], ratsimp ) )$
0 = 0
0 = 0
0 = 0
0 = 0
0 = 0
0 = 0
One often uses solve in the hope of finding useful symbolic expressions for roots of an equation. It may still be illuminating to look at the numerical values of the roots returned by the polynomial root finder allroots, which we do for the above
example:
(%i4) fpprintprec:8$
(%i5) nsolns : allroots(x6 - 1);
(%o5) [x = 0.866025 %i + 0.5, x = 0.5 - 0.866025 %i, x = 0.866025 %i - 0.5,
x = - 0.866025 %i - 0.5, x = 1.0, x = - 1.0]
(%i6) for i thru length(nsolns) do
disp ( ev( x6 - 1, nsolns[i],expand ))$
- 4.4408921E-16 %i - 5.55111512E-16
4.4408921E-16 %i - 5.55111512E-16
4.4408921E-16 %i - 5.55111512E-16
- 4.4408921E-16 %i - 5.55111512E-16
0.0
0.0
The numerical roots found by allroots satisfy the starting equation to within floating point errors.
38
Example 2
You can use solve to look for solutions to a set of equations. Here we find four sets of solutions satisfying two simultaneous
equations, and we check the solutions.
(%i1) fpprintprec:8$
(%i2) eqns : [4*x2 - y2 - 12 = 0, x*y - x - 2 = 0]$
(%i3) solns : solve(eqns,[x,y]);
(%o3) [[x = 2, y = 2], [x = 0.520259 %i - 0.133124,
y = 0.0767838 - 3.6080032 %i], [x = - 0.520259 %i - 0.133124,
y = 3.6080032 %i + 0.0767838], [x = - 1.7337518, y = - 0.153568]]
(%i4) eqns,solns[1],ratsimp;
(%o4)
[0 = 0, 0 = 0]
(%i5) for i:2 thru 4 do
disp ( ev (eqns, solns[i],expand) )$
[1.77635684E-15 - 6.66133815E-16 %i = 0, - 2.22044605E-16 = 0]
[6.66133815E-16 %i + 1.77635684E-15 = 0, - 2.22044605E-16 = 0]
[- 1.13954405E-6 = 0, - 9.38499825E-8 = 0]
(%i6) solns[4];
(%o6)
[x = - 1.7337518, y = - 0.153568]
We only use ratsimp on the first (integral) solution, which is an exact solution. For the numerical solutions, we use
instead expand. The second and third (numerical) solutions have an accuracy of about 15 digits. The fourth (numerical)
solution has about five digit accuracy.
Example 3: realroots
A Maxima user asked (on the Mailing List) how to find the value of r implied by the equation
275.0 * exp(-r) + 275.0 * exp(-2*r) + 275.0 * exp(-3*r)
+ 275.0 * exp(-4*r) + 5275.0 * exp(-5*r) = 4750.0
Straightforward use of solve does not return an explicit solution. Here is an approach suggested by Maxima developer
Stavros Macrakis.
First use rat to convert approximate numbers (275.0) to exact (275), replace exp(r) by z, and then try solve.
(%i1) fpprintprec:8$
(%i2) eqn : 275.0 * exp(-r) + 275.0 * exp(-2*r) + 275.0 * exp(-3*r)
+ 275.0 * exp(-4*r) + 5275.0 * exp(-5*r) - 4750.0 = 0$
(%i3) rat(eqn),ratprint:false;
(%o3)/R/
r 5
r 4
r 3
r 2
r
4750 (%e ) - 275 (%e ) - 275 (%e ) - 275 (%e ) - 275 %e - 5275
- ------------------------------------------------------------------- = 0
r 5
(%e )
(%i4) zeqn : ratsubst(z,exp(r),%);
5
4
3
2
4750 z - 275 z - 275 z - 275 z - 275 z - 5275
(%o4)
- ------------------------------------------------- = 0
5
z
(%i5) soln : solve(zeqn);
5
4
3
2
(%o5)
[0 = 190 z - 11 z - 11 z - 11 z - 11 z - 211]
We see that solve returned a list containing one element: a simplified form of our polynomial (in z) equation, but was
unable to return an algebraic solution. We must then consider an approximate solution, and suppose we are only interested
in real roots z, in which case we can use realroots.
39
(%i6) rr : realroots(soln[1]);
(%o6)
35805935
[z = --------]
33554432
We see that the returned real root is not very accurate, so we override the default value of rootsepsilon (which is one part
in 107 )
(%i9) rr : realroots( soln[1],1.0e-16);
38446329182573765
(%o9)
[z = -----------------]
36028797018963968
(%i10) zeqn, rr, numer;
(%o10)
- 6.5731657E-13 = 0
If z = er , then ln(z) = ln(er ) = r. We then get an accurate numerical answer for r via
(%i11) rval : log(rhs(rr[1])),numer;
(%o11)
0.0649447
(%i12) eqn, r = rval;
(%o12)
- 1.70530257E-12 = 0
x
sin(x) - 2
[x = 2 sin(x)]
40
Lets use plot2d for a quick look at this expression for positive x.
(%i3) plot2d(e,[x,0,2*%pi],
[style,[lines,5]],[ylabel," "],
[xlabel," sin(x) - x/2 " ],
[gnuplot_preamble,"set zeroaxis lw 2"])$
3
sin(x) - x/2
(1.1)
41
There are several ways one can help out solve to get the solutions we want.
Method 1 is to convert the trig functions to their complex exponential forms using exponentialize.
(%i3) eqn, exponentialize;
%i x
- %i x
%i (%e
- %e
)
%i x
- %i x
(%o3)
a (---------------------- + 1) - b (%e
+ %e
) = 0
2
(%i4) solns : solve ( %, x );
2 %i b
a
(%o4) [x = - %i log(---------- + ----------),
2 b - %i a
2 b - %i a
a
2 %i b
x = - %i log(---------- - ----------)]
2 b - %i a
2 b - %i a
(%i5) solns : solns, rectform, ratsimp;
2
2
%pi
4 b - a
4 a b
(%o5)
[x = ---, x = - atan2(---------, ---------)]
2
2
2
2
2
4 b + a
4 b + a
(%i6) eqn, solns[1], ratsimp;
(%o6)
0 = 0
(%i7) eqn, solns[2], ratsimp;
(%o7)
0 = 0
(%i8) x2 : atan2(a2 - 4*b2, 4*a*b)$
(%i9) eqn, x = x2, ratsimp;
4
2 2
4
2
3
a sqrt(16 b + 8 a b + a ) - 4 a b - a
(%o9)
- ------------------------------------------ = 0
2
2
4 b + a
(%i10) scanmap( factor, % );
(%o10)
0 = 0
(1.2)
which one would hope would be used creatively by solve to find the solutions of our equation.
Lets replace cos(x) by the symbol c and likewise replace sin(x) by the symbol s, and start with a pair of
equations.
(%i1) eqns : [a*(1-s) - 2*b*c = 0, c2 + s2 - 1 = 0]$
(%i2) solns : solve ( eqns, [s,c] );
2
2
4 b - a
4 a b
(%o2)
[[s = 1, c = 0], [s = - ---------, c = ---------]]
2
2
2
2
4 b + a
4 b + a
(%i3) eqns, solns[1], ratsimp;
(%o3)
[0 = 0, 0 = 0]
(%i4) x1soln : solve ( sin(x) = 1, x );
solve: using arc-trig functions to get a solution.
Some solutions will be lost.
%pi
(%o4)
[x = ---]
2
(%i5) eqn, x1soln, ratsimp;
(%o5)
0 = 0
42
Bearing in mind that arctan(x) = arctan(x), we get the same set of solutions using method 2.
1.8.13 Non-Rational Simplification: radcan, logcontract, rootscontract, and radexpand
The wxMaxima interface has the Simplify(r) button allows uses the radcan function on a selection. The r stands for
radcan although you could just as well think radical, since it is equivalent to the wxMaxima menu choice Simplify,
Simplify Radicals. You can also think of the work radcan as a mnenomic constructed from the capitalised letters in
RADical CANcellation, but this does not hint at the full power of this function.
The manual asserts that radcan is useful in simplifying expressions containing logs, exponentials, and radicals. Here is
an expression containing exponentials which radcan simplifies.
(%i1) expr : (exp(x)-1)/(exp(x/2)+1);
(%o1)
x
%e - 1
--------x/2
%e
+ 1
(%o2)
x
%e - 1
--------x/2
%e
+ 1
%e
- 1
We see that radcan is able to simplify this expression containing exponentials, whereas ratsimp cannot.
Here is some Xmaxima work showing the differences between the use of ratsimp, radcan, and logcontract on an
expression which is a sum of logs.
(%i4) logexpr : log ( (x+2)*(x-2) ) + log(x);
(%o4)
log((x - 2) (x + 2)) + log(x)
(%i5) logexpr, ratsimp;
2
(%o5)
log(x - 4) + log(x)
(%i6) logexpr, fullratsimp;
2
(%o6)
log(x - 4) + log(x)
(%i7) logexpr, radcan;
(%o7)
log(x + 2) + log(x) + log(x - 2)
(%i8) %, logcontract;
3
(%o8)
log(x - 4 x)
43
log(x
- 4 x)
We see that use of logcontract provided the same quality of simplification as the two step route radcan followed by
logcontract.
Here we expolore the use of radcan and rootscontract to simplify square roots:
(%i10)
(%o10)
(%i11)
(%o11)
(%i12)
(%o12)
(%i13)
(%o13)
(%i14)
(%o14)
(%i15)
(%o15)
sqrt(2)*sqrt(3), radcan;
sqrt(2) sqrt(3)
sqrt(2)*sqrt(3), rootscontract;
sqrt(6)
sqrt(6)*sqrt(3), radcan;
3 sqrt(2)
sqrt(6)*sqrt(3), rootscontract;
3 sqrt(2)
sqrt(6)/sqrt(3), radcan;
sqrt(2)
sqrt(6)/sqrt(3), rootscontract;
sqrt(2)
radexpand
The Maxima manual describes the option variable radexpand which can have the values true (the default), all, or false.
The setting of radexpand controls the automatic simplifications of radicals.
In the default case (radexpand set to true), sqrt(x2) simplifies to abs(x). This is because, by default, all symbols,
in the absence of special declarations, are considered to represent real numbers. You can declare that all symbols should
(unless declared otherwise) be considered to represent complex numbers using the domain flag, which has the default
value real.
(%i16) sqrt(x2);
(%o16)
(%i17) domain:complex$
(%i18) sqrt(x2);
(%o18)
(%i19) domain:real$
(%i20) sqrt(x2);
(%o20)
abs(x)
2
sqrt(x )
abs(x)
Next we show the simplifications which occur to the expression sqrt(16*x2) for the three possible values of radexpand.
(%i21)
(%o21)
(%i22)
(%o22)
(%i23)
(%i24)
(%o24)
(%i25)
(%i26)
(%o26)
radexpand;
true
sqrt(16*x2);
4 abs(x)
radexpand:all$
sqrt(16*x2);
4 x
radexpand:false$
sqrt(16*x2);
2
sqrt(16 x )
44
1.8.14 Trigonometric Simplification: trigsimp, trigexpand, trigreduce, and trigrat
Here are simple examples of the important trig simplification functions trigsimp, trigexpand, trigreduce, and trigrat.
trigsimp converts trig functions to sines and cosines and also attempts to use the identiy cos(x)2 + sin(x)2 = 1.
(%i1) trigsimp(tan(x));
(%o1)
sin(x)
-----cos(x)
The manual entry for trigsimp advises that trigreduce, ratsimp, and radcan may be able to further simplify the result.
The author has the following function defined in mbe1util.mac, which is loaded in during startup.
rtt(e) := radcan ( trigrat ( trigsimp (e)))$
This function can be equivalent to trigreduce if only sines and cosines are present, but otherwise may return different
forms, as we show here, comparing the opposide effects of trigexpand and trigreduce. Note that trigexpand expands
trig functions of sums of angles and/or trig functions of multiple angles (like 2*x at the top level, and the user should
read the manual description to see options available.
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
e: sin(x+y), trigexpand;
cos(x) sin(y) + sin(x) cos(y)
e, trigreduce;
sin(y + x)
rtt (e);
sin(y + x)
e : tan(x+y), trigexpand;
tan(y) + tan(x)
(%o8)
----------------1 - tan(x) tan(y)
(%i9) e, trigreduce;
tan(y)
tan(x)
(%o9)
- ----------------- - ----------------tan(x) tan(y) - 1
tan(x) tan(y) - 1
(%i10) %, ratsimp;
tan(y) + tan(x)
(%o10)
- ----------------tan(x) tan(y) - 1
(%i11) rtt (e);
sin(y + x)
(%o11)
---------cos(y + x)
(%i12) trigsimp( tan(x+y) );
sin(y + x)
(%o12)
---------cos(y + x)
(%i13) e : cosh(x + y), trigexpand;
(%o13)
sinh(x) sinh(y) + cosh(x) cosh(y)
(%i14) e, trigreduce;
(%o14)
cosh(y + x)
45
(%o15)
- y - x
2 y + 2 x
%e
(%e
+ 1)
--------------------------2
(%i16) expand(%);
(%o16)
y + x
- y - x
%e
%e
------- + --------2
2
In the following, note the difference when using trigexpand(expr) compared with ev ( expr, trigexpand ).
This difference is due to the fact that trigexpand has both the evfun and the evflag properties.
(%i1) e1 : trigexpand( tan(2*x + y) );
tan(y) + tan(2 x)
(%o1)
------------------1 - tan(2 x) tan(y)
(%i2) e2 : tan (2*x + y), trigexpand;
2 tan(x)
tan(y) + ----------2
1 - tan (x)
(%o2)
-------------------2 tan(x) tan(y)
1 - --------------2
1 - tan (x)
(%i3) rtt (e1);
sin(y + 2 x)
(%o3)
-----------cos(y + 2 x)
(%i4) rtt (e2);
sin(y + 2 x)
(%o4)
-----------cos(y + 2 x)
(%i5) trigsimp (e1);
cos(2 x) sin(y) + sin(2 x) cos(y)
(%o5)
- --------------------------------sin(2 x) sin(y) - cos(2 x) cos(y)
(%i6) trigsimp (e2);
2
(2 cos (x) - 1) sin(y) + 2 cos(x) sin(x) cos(y)
(%o6)
- ----------------------------------------------2
2 cos(x) sin(x) sin(y) + (1 - 2 cos (x)) cos(y)
46
1.8.15 Complex Expressions: rectform, demoivre, realpart, imagpart, and exponentialize
Sec. 6.2 of the Maxima manual has the introduction
A complex expression is specified in Maxima by adding the real part of the expression to %i times the imaginary part. Thus the roots of the equation x2 - 4*x + 13 = 0 are 2 + 3*%i and 2 - 3*%i. Note that
simplification of products of complex expressions can be effected by expanding the product. Simplification
of quotients, roots, and other functions of complex expressions can usually be accomplished by using the
realpart, imagpart, rectform, polarform, abs, carg functions.
Here is a brief look at some of these functions, starting with exponentialize.
(%i1) cform : [cos(x),sin(x),cosh(x)], exponentialize;
%i x
- %i x
%i x
- %i x
x
- x
%e
+ %e
%i (%e
- %e
) %e + %e
(%o1)
[-----------------, - ----------------------, -----------]
2
2
2
(%i2) cform, demoivre;
x
- x
%e + %e
(%o2)
[cos(x), sin(x), -----------]
2
(%i3) cform, rectform;
x
- x
%e + %e
(%o3)
[cos(x), sin(x), -----------]
2
(%i4) realpart ( cform );
x
- x
%e + %e
(%o4)
[cos(x), sin(x), -----------]
2
(%i5) imagpart ( cform );
(%o5)
[0, 0, 0]
1
(sin(2) sin(2 x) + cos(2) cos(2x) + 1)
2
(1.3)
is true. Although it is not difficult to show the equivalence using the standard Maxima tools (see Sec. 10.3.6 in Ch.10),
we use here zeroequiv.
(%i1) e1:cos(x-1)2;
2
(%o1)
cos (x - 1)
(%i2) e2 : (sin(2)*sin(2*x)+cos(2)*cos(2*x)+1)/2;
sin(2) sin(2 x) + cos(2) cos(2 x) + 1
(%o2)
------------------------------------2
(%i3) zeroequiv ( e1-e2, x );
(%o3)
true
An alternative (and complementary) approach is to plot both expressions e1 and e2 on the same plot.
47
1.9 User Defined Maxima Functions: define, fundef, block, and local
A Maxima function can be defined using the := operator. The left side of the function definition should be the name
of the function followed by comma separated formal parameters enclosed in parentheses. The right side of the Maxima
function definition is the function body. When a Maxima function is called, the formal parameters are bound to the call
arguments, any free variables in the function body take on the values that they have at the time of the function call, and
the function body is evaluated. You can define Maxima functions which are recursive to an arbitrary depth (of course
there are always practical limits due to memory, speed,...). After a Maxima function is defined, its name is added to the
Maxima list functions.
Problems may sometimes arise when passing to a Maxima function (as one of the calling arguments) an expression which
contains a variable with the same name as a formal parameter used in the function body (name conflicts).
1.9.1 A Function Which Takes a Derivative
In this section we discuss a question sent in to the Maxima Mailing List (which we paraphrase).
I want to make the derivative of a function a function itself.
Naively, I tried the following.
First define a Maxima function f(x) as a simple polynomial.
Next define a second Maxima function fp(x) ("f-prime")
which will take the first derivative of f(x).
Then try to use fp(x) to get the derivative of f at x =1.
This did not work, as shown here:
-----------------------------------------------(%i1) f(x):= -2*x3 + 3*x2 + 12*x - 13$
(%i2) fp(x):= diff(f(x),x)$
(%i3) fp(1);
diff: second argument must be a variable; found 1
#0: fp(x=1)
-- an error. To debug this try debugmode(true);
--------------------------------------------What can I do?
Thanks
The error message returned by Maxima in response to input %i3 means that Maxima determined that the job requested
was to return the result of the operation diff( f(1), 1 ). In other words, variable substitution occurred before
differentiation, whereas, what is wanted is first differentiation, and then variable substitution.
Lets pick a simpler function, and compare three ways to try to get this job done.
(%i1) f(y) := y3;
3
(%o1)
(%i2) f(z);
f(y) := y
3
(%o2)
z
(%i3) f1(x) := diff ( f(x), x);
(%o3)
f1(x) := diff(f(x), x)
(%i4) f2(x) := (diff ( f(x), x));
2
(%o4)
f2(x) := 3 x
(%i5) define ( f3(x), diff ( f(x), x) );
2
(%o5)
f3(x) := 3 x
48
As long as we request the derivative of f(z), where z is treated as an undefined variable (ie., z has not been bound to
a number, in which case numberp(z) will return false), all three definitions give the correct result. But when we
request the derivative at a specific numerical point, only the last two methods give the correct result without errors, and
the first (delayed assignment operator method) does not work.
Note that the quote-quote method requires two single quotes, and we need to surround the whole expression with
parentheses: (...). This quote-quote method is available only in interactive use, and will not work inside another
function, as you can verify. The conventional wisdom denigrates the quote-quote method and advises use of the define
method.
The define function method can not only be used interactively, but also when one needs to define a function like this
inside another Maxima function, as in
(%i9) dplay(g,a,b) := block ( [val1,val2 ],
local (dg),
define ( dg(y), diff (g(y), y)),
val1 : g(a) + dg(a),
val2 : g(b) + dg(b),
display (val1,val2),
val1 + val2)$
(%i10) g(x) := x;
(%o10)
g(x) := x
(%i11) dplay(g,1,1);
val1 = 2
val2 = 2
(%o11)
(%i12) g(x) := x2;
4
2
(%o12)
(%i13) dplay(g,1,2);
g(x) := x
val1 = 3
val2 = 8
(%o13)
(%i14) dg(3);
(%o14)
11
dg(3)
You can find the manual discussion of the quote-quote operator near the top of the index list where misc. symbols are
recorded. There you find the comment Applied to the operator of an expression, quote-quote changes the operator from
a noun to a verb (if it is not already a verb).
The use of local inside our Maxima function dplay prevents our definition of the Maxima function dg from leaking out
into the top level context and keeps the knowledge of dg inside dplay and any user defined Maxima functions which are
called by dplay, and inside any user defined Maxima functions which are called by those functions, etc...
49
Maxima developer Stavros Macrakis has posted a good example which emphasizes the difference between the delayed
assignment operator := and the define function. This example uses Maximas print function.
(%i1) f1(x):=print (x)$
(%i2) define ( f2(x), print (x) )$
x
Notice that the delayed assignment definition for f1 did not result in the actual operation of print(x), whereas the define
definition of f2 resulted in the operation of print(x), as you can see on your screen after input %i2. Quoting from
Macrakis:
In the case of :=, both arguments are unevaluated. This is the normal way function definitions work in
most programming languages.
In the case of define, the second argument is evaluated normally [in the process of absorbing the definition], not unevaluated. This allows you to *calculate* a definition.
We can see the difference between f1 and f2 by using fundef, which returns what Maxima has accepted as a definition in
the two cases.
(%i3) fundef (f1);
(%o3)
(%i4) fundef (f2);
(%o4)
f1(x) := print(x)
f2(x) := x
Lets now compare these definitions at runtime. f1 will print its argument to the screen, but f2 will not, since in the latter
case, all reference to Maximas print function has been lost.
(%i5) f1(5);
5
(%o5)
(%i6) f2(5);
(%o6)
5
5
Macrakis continues:
define is useful for calculating function definitions which will later be applied to arguments. For example, compare:
(%i7) define (f(x), optimize (horner (taylor (tanh(x),x,0,8),x)));
2 x (%1 (%1 (42 - 17 %1) - 105) + 315)
(%o7) f(x) := block([%1], %1 : x , ------------------------------------)
315
(%i8) f(0.1);
(%o8)
0.099667994603175
(%i9) g(x) := optimize (horner (taylor (tanh(x),x,0,8),x));
(%o9)
g(x) := optimize(horner(taylor(tanh(x), x, 0, 8), x))
(%i10) g(0.1);
Variable of expansion cannot be a number: 0.1
#0: g(x=0.1)
-- an error. To debug this try debugmode(true);
50
1.9.2 Lambda Expressions
Lambda notation is used to define unnamed anonymous Maxima functions. Lambda expressions allow you to define
a special purpose function which will not be used in other contexts (since the function has no name, it cannot be used later).
The general syntax is
lambda ( arglist, expr1, expr2, ...,exprn )
where arglist has the form [x1, x2, ...,xm] and provide formal parameters in terms of which the expr1, expr2,...
can be written, (use can also be made of %% to refer to the result of the previous expression exprj). When this function
is evaluated, unbound local variables x1,x2,... are created, and then expr1 through exprn are evaluated in turn.
The return value of this function is exprn.
(%i1) functions;
(%o1) [qplot(exprlist, prange, [hvrange]), rtt(e), ts(e, v), to_atan(e, y, x),
to_atan2(e, y, x), totan(e, v), totan2(e, v), mstate(), mattrib(), mclean(),
fll(x)]
(%i2) f : lambda([x,y],x2 + y3);
2
3
(%o2)
lambda([x, y], x + y )
(%i3) f (1,1);
(%o3)
2
(%i4) f(2,a);
3
(%o4)
a + 4
(%i5) apply ( f, [1,2] );
(%o5)
9
(%i6) functions;
(%o6) [qplot(exprlist, prange, [hvrange]), rtt(e), ts(e, v), to_atan(e, y, x),
to_atan2(e, y, x), totan(e, v), totan2(e, v), mstate(), mattrib(), mclean(),
fll(x)]
(%i7) map ( sin, [1,2,3] );
(%o7)
[sin(1), sin(2), sin(3)]
(%i8) map ( lambda([x],x2 + sin(x) ),[1,2,3] );
(%o8)
[sin(1) + 1, sin(2) + 4, sin(3) + 9]
(%i9) lambda ([x],x+1 )(3);
(%o9)
4
51
(%i6) myfac(4);
1 Enter myfac [4]
2 Enter myfac [3]
3 Enter myfac [2]
4 Enter myfac [1]
5 Enter myfac [0]
5 Exit myfac 1
4 Exit myfac 1
3 Exit myfac 2
2 Exit myfac 6
1 Exit myfac 24
(%o6)
24
(%i7) untrace(myfac);
(%o7)
[myfac]
(%i8) [myfac(4),factorial(4),4!];
(%o8)
[24, 24, 24]
Legendre Polynomial
As a second example of a recursive definition of a Maxima function, one can define the Legendre polynomial Pn (x) via
a recursive relation that relates three different n values (for a given x). We can check our design by using the Maxima
function legendre p (n,x), which is part of the orthogonal polynomial package orthopoly.lisp.
(%i1) p(n,x) := if n=0 then 1 elseif n=1 then x else
expand( ( (2*n-1)/n )*x*p(n-1,x) - ((n-1)/n)*p(n-2,x) )$
(%i2) [p(0,x),p(1,x),p(2,x),p(3,x)];
2
3
3 x
1 5 x
3 x
(%o2)
[1, x, ---- - -, ---- - ---]
2
2
2
2
(%i3) map ( lambda([nn], p (nn,x) ),[0,1,2] );
2
3 x
1
(%o3)
[1, x, ---- - -]
2
2
(%i4) map ( lambda([nn], expand (legendre_p (nn,x))),[0,1,2] );
2
3 x
1
(%o4)
[1, x, ---- - -]
2
2
f (x) := x
k
(%i2) arrays;
(%o2)
(%i3) makelist ( f[nn](y),nn,0,3 );
+ 1
[f]
2
(%o3)
(%i4) arrayinfo(f);
(%o4)
[2, y + 1, y
3
+ 1, y
+ 1]
52
Here is a example which uses Maximas anonymous lambda function to define a subscripted function which does the
same job as above.
(%i1) h[nn] := lambda ([xx], xxnn + 1);
nn
(%o1)
:= lambda([xx], xx
+ 1)
nn
(%i2) arrays;
(%o2)
(%i3) arrayinfo(h);
(%o3)
(%i4) h[2];
[f, h]
[hashed, 1]
2
(%o4)
(%i5) arrayinfo(h);
(%o5)
(%i6) h[2](y);
lambda([xx], xx
+ 1)
[hashed, 1, [2]]
2
(%o6)
y + 1
(%i7) map ( lambda ( [mm], h[mm](x) ),[0,1,2,3] );
2
3
(%o7)
[2, x + 1, x + 1, x + 1]
(%i8) arrayinfo(h);
(%o8)
[hashed, 1, [0], [1], [2], [3]]
We see in the above example that elements 1 through 4 were computed when the call a[4] was first made. Once
the array elements have been computed, they are not recomputed, even though our definition changes. Note that after
(%i8) a[n] := n/2$, our interogation (%i9) a[4]; does not return our new definition, but the result of the
original calculation. If you compute a[50] using our first recursive factorial definition, all values a[1] through a[50]
are remembered. Computing a[51] then takes only one step.
53
1.9.6 Recursive Subscripted Maxima Functions
We here use a subscripted function to achieve a recursive definition of a Legendre polynomial Pn (x). (The author
thanks Maxima developer Richard Fateman for this example.)
(%i1) ( p[n](x) := expand(((2*n-1)/n)*x*p [n-1](x) - ((n-1)/n)*p [n-2](x) ),
p [0](x) := 1, p [1](x) := x ) $
(%i2) makelist( p[m](x),m,0,4 );
2
3
4
2
3 x
1 5 x
3 x 35 x
15 x
3
(%o2)
[1, x, ---- - -, ---- - ---, ----- - ----- + -]
2
2
2
2
8
4
8
(%i3) arrays;
(%o3)
[p]
(%i4) arrayinfo(p);
(%o4)
[hashed, 1, [0], [1], [2], [3], [4]]
(%i5) [p[3](x),p[3](y)];
3
3
5 x
3 x 5 y
3 y
(%o5)
[---- - ---, ---- - ---]
2
2
2
2
(%i6) map ( lambda([nn], p[nn](x)),[0,1,2,3] );
2
3
3 x
1 5 x
3 x
(%o6)
[1, x, ---- - -, ---- - ---]
2
2
2
2
If you want a visual reminder of the bindings, then the [job1,job2,..] notation is more appropriate.
(%i8) [ a:1, b:2/3, c : cos(4/3) ];
(%o8)
2
4
[1, -, cos(-)]
3
3
54
(%i4) float(p3t);
(%o4)
(%i5) ?print(%);
0.080000000000000002
(%o5)
(%i6) p3f : p3, x = 0.8;
(%o6)
(%i7) ?print(%);
0.080000000000000071
(%o7)
(%i8) abs (p3f - p3t);
(%o8)
(%i9) abs (%o4 - p3t);
(%o9)
(%i10) ?print(%);
0.0
(%o10)
0.08
0.08
0.08
0.08
6.9388939039072284E-17
0.0
0.0
The input line (%i6) p3f : p3, x = 0.8; replaces x by the floating point decimal number 0.8 (which has no
exact binary representation) and then uses binary arithmetic to perform the indicated additions, divisions, and multiplications, and then returns the closest decimal number corresponding to the final binary value. The result of all this hidden
work is a number with some floating point error, which we calculate in line %i8.
We can come to the same conclusion in a slightly different way if we first define a Maxima function P3(x) using
p[3], say.
(%i11) define (P3(y), p[3](y))$
(%i12) P3(x);
(%o12)
3
5 x
3 x
---- - --2
2
We have used ?print(...) above to look at the approximate decimal digit equivalent of a binary representation held
internally by Maxima for a floating point number. We can sometimes learn new things by looking at Lisp translations of
input and output using ?print( Maxima stuff ), :lisp #$ Maxima stuff $, and :lisp $_. (See html
Help Manual: Click on Right Panel, Click on Contents, Sec. 3.1, Lisp and Maxima.)
(%i18) ?print(a + b)$
((MPLUS SIMP) $A $B)
(%i19) :lisp $_
((PRINT) ((MPLUS) $A $B))
(%i19) :lisp #$a+b$
((MPLUS SIMP) $A $B)
(%i19) ?print( a/b )$
((MTIMES SIMP) $A ((MEXPT SIMP) $B -1))
(%i20) :lisp $_
((PRINT) ((MQUOTIENT) $A $B))
55
We see above that rat does not pull out all the common factors in this second example. We also find that factor does not
simply pull out factors, but also rewrites the trig functions, when used with the first expression.
(%i8) factor (e1);
(%o8)
2
2
- (cos(d2) - cos(d1)) (cos (d2) + cos(d1) cos(d2) + cos (d1)) x A
More discussion of display and simplification tools will appear in the upcoming new Chapter 4.
56
Note that to avoid an error return on the floating point division test, we needed to use for
the answer the result returned by the Lisp print function, which is available from Maxima by
preceding the Lisp function name with a question mark (?).
57
2.1.1
0.8
sin(u)
0.6
0.4
0.2
0
0
0.2
0.4
0.6
0.8
u
1.2
1.4
4
While viewing the resulting plot, use of the two-key command Alt-Spacebar, which normally (in Windows) brings up
a resizing menu, instead switches from the gnuplot figure to a raw gnuplot window. You can get back to the figure using
Alt-Tab, but the raw gnuplot window remains in the background. You should resize the figure window by clicking on
the Maximize (or Restore) icon in the upper right-hand corner. Both the figure and the raw gnuplot window disappear
when you close (using, say Alt-F4, twice: once to close the figure window, and once to close the raw gnuplot window).
Returning to the drawn plot, we see that plot2d has made the canvas width only as wide as the drawing width, and has
made the canvas height only as high as the drawing height. Now lets add a horizontal range (canvas width) control list in
the form [x,-0.2,1.8]. Notice the special role the symbol x plays here in plot2d. u is a plot parameter, and x is
a horizontal range control parameter.
(%i2) plot2d ( sin(u),[u,0,%pi/2],[x, -0.2, 1.8] )$
0.8
sin(u)
0.6
0.4
0.2
0
0
0.5
1.5
However, if the expression variable happens to be x, the following command includes both draw width and canvas width
using separate x symbol control lists, and results in the correct plot:
(%i4) plot2d ( sin(x), [x,0,%pi/2], [x,-0.2,1.8] )$
in which the first (required) x drawing parameter list determines the drawing range, and the second (optional) x control
list determines the canvas width.
Despite the special role the symbol y also plays in plot2d, the following command produces the same plot as above.
(%i5) plot2d ( sin(y), [y,0,%pi/2], [x,-0.2,1.8] )$
5
The optional vertical canvas height control list uses the special symbol y, as shown in
(%i6) plot2d ( sin(u), [u,0,%pi/2], [x,-0.2,1.8], [y,-0.2, 1.2] )$
which produces
1.2
0.8
sin(u)
0.6
0.4
0.2
-0.2
0
0.5
1.5
2.1.2
Parametric Plots
For orientation, we will draw a sine curve using the parametric plot object syntax and using a parametric parameter t.
(%i1) plot2d ( [parametric, t, sin(t), [t, 0, %pi] ] )$
which produces
1
0.8
sin(t)
0.6
0.4
0.2
0
0
0.5
1.5
2.5
3.5
6
As the plot2d section of the manual asserts, the general syntax for a plot2d parametric plot is
plot2d (... [parametric,x_expr,y_expr,t_range],...)
in which t_range has the form of a list: [t,tmin,tmax] if the two expressions are functions of t, say. There is no
restriction on the name used for the parametric parameter.
We see that
plot2d ( [ parametric,
fx(t),
plots pairs of points ( fx (ta), fy(ta) ) for ta in the interval [tmin, tmax]. We have used no canvas
width control list [ x, xmin, xmax ] in this minimal version.
2.1.3
This is a messy subject. We will only consider the separate gnuplot window mode (not the embedded plot mode) and
assume a maximized gnuplot window (as large as the monitor allows).
We use a parametric plot to create a circle, letting fx(t) = cos(t) and fy(t) = sin(t), and again adding no
canvas width or height control lists.
(%i2) plot2d ([parametric, cos(t), sin(t), [t,-%pi,%pi]])$
If this plot is viewed in a maximized gnuplot window, the height to width ratio is about 0.6 on the authors equipment.
The corresponding eps file for the figure included here has a height to width ratio of about 0.7 when viewed with GSView,
and about the same ratio in this pdf file:
1
sin(t)
0.5
-0.5
-1
-1
-0.5
0
cos(t)
0.5
7
There are two approaches to better roundness. The first approach is to use the plot2d option
[gnuplot_preamble,"set size ratio 1;"], as in
(%i3) plot2d ([parametric, cos(t), sin(t), [t,-%pi,%pi]],
[gnuplot_preamble,"set size ratio 1;"])$
With this command, the author gets a height to width ratio of about 0.9 using the fullscreen gnuplot window choice. The
eps file save of this figure, produced with the code
plot2d ([parametric, cos(t), sin(t), [t,-%pi,%pi]],
[gnuplot_preamble,"set size ratio 1;"],
[psfile,"ch2p06.eps"] )$
had a height to width ratio close to 1 when viewed with GSView and close to that value in this pdf file:
1
sin(t)
0.5
-0.5
-1
-1
-0.5
0
cos(t)
0.5
has a height to width ratio of about 1.0 (fullscreen Gnuplot window) on the authors equipment. Notice above that the
vertical range is determined by the curve properties and extends over (y= -1, y = 1). The y-range here is 2, the
x-range is 3.2, so the x-range is 1.6 times the y-range.
8
We now make a plot consisting of two plot objects, the first being the explicit expression u3, and the second being the
parametric plot object used above. We now need the syntax
plot2d ([plot-object-1, plot-object-2], possibly-required-draw-range-control,
other-option-lists )
Here is an example :
(%i5) plot2d ([u3,[parametric, cos(t), sin(t), [t,-%pi,%pi]]],
[u,-1.1,1.1],[x,-1.5,1.5],[y,-1.5,1.5],
[gnuplot_preamble,"set size ratio 1;"])$
in which [u,-1.1,1.1] is required to determine the drawing range of u3, and we have added separate horizontal
and vertical canvas control lists as well as the gnuplot preamble option to approximate a circle, since it is quicker than
fiddling with the x and y ranges by hand.
To get the corresponding eps file figure for incorporation in this pdf file, we used the code
plot2d ([u3,[parametric, cos(t), sin(t), [t,-%pi,%pi]]],
[u,-1.1,1.1],[x,-1.5,1.5],[y,-1.5,1.5],
[gnuplot_preamble,"set size ratio 1;"],
[psfile,"ch2p07.eps"])$
which produces
1.5
u3
cos(t), sin(t)
0.5
-0.5
-1
-1.5
-1.5
-1
-0.5
0
u
0.5
1.5
9
We now add a few more options to make this combined plot look cleaner and brighter (more about some of these later).
(%i6) plot2d (
[ [parametric, cos(t), sin(t), [t,-%pi,%pi],[nticks,200]],u3],
[u,-1,1], [x,-1.2,1.2] , [y,-1.2,1.2],
[style, [lines,8]], [xlabel," "], [ylabel," "],
[box,false], [axes, false],
[legend,false],[gnuplot_preamble,"set size ratio 1;"])$
and the corresponding eps file (with [lines,20] for increased line width) produces:
Each element to be included in the plot can have a separate [ lines, nlw, nlc ] entry in the style option list, with nlw
determining the line width and nlc determining the line color. The default value of nlw is 1, a very thin weak line. The
use of nlw = 5 creates a strong wider line.
The default color choices (if you dont provide a specific vlue of nlc) consist of a rotating color scheme which starts
with nlc = 1 (blue) and then progresses through nlc = 6 (cyan = greenish-blue) and then repeats.
10
You will see the colors with the associated values of nlc, using the following code which draws a set of vertical lines in
various colors (a version of a histogram). This code also shows an example of using discrete list objects (to draw straight
lines), and the use of various options available. You should run this code with your own hardware-software setup, to see
what the default plot2d colors are with your system.
(%i1) plot2d(
[ [discrete,[[0,0],[0,5]]], [discrete,[[2,0],[2,5]]],
[discrete,[[4,0],[4,5]]],[discrete,[[6,0],[6,5]]],
[discrete,[[8,0],[8,5]]],[discrete,[[10,0],[10,5]]],
[discrete,[[12,0],[12,5]]],[discrete,[[14,0],[14,5]]] ],
[style, [lines,6,0],[lines,6,1],[lines,6,2],
[lines,6,3],[lines,6,4],[lines,6,5],[lines,6,6],
[lines,6,7]],
[x,-2,20],
[y,-2,8],
[legend,"0","1","2","3","4","5","6","7"],
[xlabel," "],
[ylabel," "],
[box,false],[axes,false])$
Note that none of the objects being drawn are expressions or functions, so a draw parameter range list is not only not
necessary but would make no sense, and that the optional horizontal canvas width control list above is [x,-2,20].
The interactive gnuplot plot2d colors available on a Windows XP system (using XMaxima with Maxima ver. 5.31) thus
are: 0 = cyan, 1 = blue, 2 = red, 3 = green, 4 = majenta, 5 = black, 6 = cyan, 7 = blue, 8 = red, ...
Adding the element [psfile,"c:/work2/ztest2.eps"] to the above plot2d code produces the figure displayed here:
0
1
2
3
4
5
6
7
11
For a simple example which uses color and line width controls, we plot the expressions u2 and u3 on the same canvas,
using lines in black and red colors, and add a height control list, which has the syntax [y, ymin, ymax].
(%i2) plot2d( [u2,u3],[u,0,2], [x, -.2, 2.5],
[style, [lines,5,5],[lines,5,2]],
[y,-1,4] )$
plot2d: some values were clipped.
u3
u
-1
0
0.5
1.5
2.5
2.1.5
We have seen some simple parametric plot examples above. Here we make a more elaborate plot which includes discrete data points which locate on the curve special places, with information on the key legend about those special
points. The actual parametric curve color is chosen to be black (5) with some thickness (4), using [lines,4,5]
in the style list. We force large size points with special color choices, using the maximum amount of control in the
[points, nsize, ncolor, ntype] style assignments.
(%i1) obj_list : [ [parametric, 2*cos(t),t2,[t,0,2*%pi]],
[discrete,[[2,0]]],[discrete,[[0,(%pi/2)2]]],
[discrete,[[-2,%pi2]]],[discrete,[[0,(3*%pi/2)2]]] ]$
(%i2) style_list : [style, [lines,4,5],[points,5,1,1],[points,5,2,1],
[points,5,3,1],[points,5,4,1]]$
(%i3) legend_list : [legend, " ","t = 0","t = pi/2","t = pi",
" t = 3*pi/2"]$
(%i4) plot2d( obj_list, [x,-3,4], [y,-1,40],style_list,
[xlabel,"X = 2 cos( t ), Y = t 2 "],
[ylabel, " "] ,legend_list )$
12
This produces the plot:
40
t=0
t = pi/2
t = pi
t = 3*pi/2
35
30
25
20
15
10
5
0
-3
-2
-1
X = 2 cos( t ), Y = t
13
[style,[points,5]],[xlabel,""],[ylabel,""],
[x,-0.2,1],[y,-0.2,0.7],
[box,false],[axes,false],[legend,false])$
which will produce something like
Figure 12: default point colors and styles, 1-8, then 9-16
You can also experiment with one shape at a time by defining a function dopt(n) which selects the shape with the
integer n and leaves the color blue:
dopt(n) := plot2d ([discrete,[[0,0]]],[style,[points,15,1,n]],
[box,false],[axes,false],[legend,false])$
Next we combine a list of twelve (x,y) pairs of points with the key word discrete to form a discrete object type for plot2d,
and then look at the data points without adding the optional canvas width control. Note that using only one discrete list
for all the points results in all data points being displayed with the same size, color and shape.
(%i5) data_list : [discrete,
[ [1.1,-0.9],[1.45,-1],[1.56,0.3],[1.88,2],
[1.98,3.67],[2.32,2.6],[2.58,1.14],
[2.74,-1.5],[3,-0.8],[3.3,1.1],
[3.65,0.8],[3.72,-2.9] ] ]$
(%i6) plot2d( data_list, [style,[points]])$
14
This produces the plot
4
-1
-2
-3
1
1.5
2.5
x
3.5
Figure 13: Twelve Data Points with Same Size, Color, and Shape
We now combine the data points with a curve which is a possible fit to these data points over the draw parameter range
[u, 1, 4].
(%i7) plot2d( [sin(u)*cos(3*u)*u2, data_list],
[u,1,4], [x,0,5],[y,-10,8],
[style,[lines,4,1],[points,4,2,1]])$
plot2d: some values were clipped.
u2*sin(u)*cos(3*u)
discrete2
6
4
2
0
-2
-4
-6
-8
-10
0
3
u
15
2.1.6
Here is an example of using the gnuplot preamble options to add a grid, a title, and position the plot key at the bottom
center of the canvas. Note the use of a semi-colon between successive gnuplot instructions.
(%i1) plot2d([ u*sin(u),cos(u)],[u,-4,4] ,[x,-8,8],
[style,[lines,5]],
[gnuplot_preamble,"set grid; set key bottom center;
set title Two Functions;"])$
Two Functions
2
1.5
1
0.5
0
-0.5
-1
-1.5
-2
-2.5
-3
u*sin(u)
cos(u)
-3.5
-8
-6
-4
-2
0
u
16
2.1.7
The first method of exporting plot2d drawings as special graphics files is to have the plot drawn in the Gnuplot window
(either the XMaxima route, or using wxplot2d rather than plot2d if you are using wxmaxima). Then left-click the
left-most Gnuplot icon near the top of the Gnuplot window (copy the plot to clipboard). Then open an application
which accomodates the graphics format you desire, and paste the clipboard image into the application, and then use Save
As, selecting the graphics type of save desired.
The second method of exporting plot2d drawings as special graphics files is to use the gnuplot_term option as part
of your plot2d command. If you do not add an additional option of the form (for example)
[gnuplot_out_file, "c:/k1/myname.ext"]
where ext is replaced by an appropriate graphics type extension, then plot2d creates a file with the name maxplot.ext
in your current working directory.
For example,
(%i1) plot2d (sin(u),[u,0,%pi], [gnuplot_term,jpeg])$
will overwrite the previous file maxplot.jpeg to create the new graphics file for the plot of cos. To provide a different
name for different plots, you would write, for example,
(%i3) plot2d (cos(u),[u,0,%pi],
[gnuplot_out_file,"c:/work2/mycos1.jpeg"],
[gnuplot_term,jpeg])$
If you do not supply the complete path, the file is written in the /bin folder of the Maxima program installation. Turning
to other graphics file formats, and ignoring the naming option part,
(%i4) plot2d (sin(u),[u,0,%pi],
[gnuplot_term,png])$
will create maxplot.pdf, which will be the cleanest plot of the above cases.
17
2.1.8
The file qplot.mac is posted with Ch. 2 and contains a function called qplot which can be used for quick plotting of
functions in place of plot2d.
The function qplot (q for quick) accepts the default cyclic colors but always uses thicker lines than the plot2d default,
adds more prominent x and y axes to the plot, and adds a grid (which can be switched off using the third from the left
gnuplot icon). Here are some examples of use. (We include use with discrete lists only for completeness, since there is
no way to get the points style with qplot.)
(%i1)
(%o1)
(%i2)
(%i3)
(%i4)
(%i5)
(%i6)
(%i7)
(%i8)
load(qplot);
c:/work2/qplot.mac
qplot(sin(u),[u,-%pi,%pi])$
qplot(sin(u),[u,-%pi,%pi],[x,-4,4])$
qplot(sin(u),[u,-%pi,%pi],[x,-4,4],[y,-1.2,1.2])$
qplot([sin(u),cos(u)],[u,-%pi,%pi])$
qplot([sin(u),cos(u)],[u,-%pi,%pi],[x,-4,4])$
qplot([sin(u),cos(u)],[u,-%pi,%pi],[x,-4,4],[y,-1.2,1.2])$
qplot ([parametric, cos(t), sin(t), [t,-%pi,%pi]],
[x,-2.1,2.1],[y,-1.5,1.5])$
The last use involved only a parametric object, and the list [x,-2.1,2.1] is interpreted as a horizontal canvas width
control list based on the symbol x.
While viewing the resulting plot, use of the two-key command Alt-Spacebar, which normally brings up a resizing menu, instead
switches from the gnuplot figure to a raw gnuplot window. You can get back to the figure using Alt-Tab, but the raw gnuplot
window remains in the background. You should resize the figure window by clicking on the Maximize (or Restore) icon in the upper
right-hand corner. Both the figure and the raw gnuplot window disappear when you close (using, say Alt-F4, twice: once to close
the figure window, and once to close the raw gnuplot window).
The next example includes both an expression depending on the parameter u and a parametric object depending on a parameter t, so
we must have a expression draw list of the form: [u,umin,umax].
(%i9) qplot ([ u3,
[parametric, cos(t), sin(t), [t,-%pi,%pi]]],
[u,-1,1],[x,-2.25,2.25],[y,-1.5,1.5])$
0.5
-0.5
-1
-1.5
-2
-1.5
-1
-0.5
0
u
0.5
1.5
18
To get the same plot using plot2d from scratch requires the code:
plot2d([ u3, [parametric, cos(t), sin(t), [t,-%pi,%pi]]],
[u,-1,1],[x,-2.25,2.25],[y,-1.5,1.5],
[style,[lines,5]], [nticks,100],
[gnuplot_preamble, "set grid; set zeroaxis lw 5;"],
[legend,false],[ylabel, " "])$
Here are two discrete examples which draw vertical lines.
(%i10) qplot([discrete,[[0,-2],[0,2]]],[x,-2,2],[y,-4,4])$
(%i11) qplot( [ [discrete,[[-1,-2],[-1,2]]],
[discrete,[[1,-2],[1,2]]]],[x,-2,2],[y,-4,4])$
Here is the code (in qplot.mac) which defines the Maxima function qplot.
qplot ( exprlist, prange, [hvrange]) :=
block([optlist, plist],
optlist : [ [nticks,100], [legend, false],
[ylabel, " "], [gnuplot_preamble, "set grid; set zeroaxis lw 5;"] ],
optlist : cons ( [style,[lines,5]], optlist ),
if length (hvrange) = 0 then plist : []
else
plist : hvrange,
plist : cons (prange,plist),
plist : cons (exprlist,plist),
plist : append ( plist, optlist ),
apply (plot2d, plist ) )$
In this code, the third argument is an optional argument. The local plist accumulates the arguments to be passed to plot2d
by use of cons and append, and is then passed to plot2d by the use of apply. The order of using cons makes sure that
exprlist will be the first element, (and prange will be the second) seen by plot2d. In this example you can see several
tools used for programming with lists.
Several choices have been made in the qplot code to get quick and uncluttered plots of one or more functions. One choice
was to add a grid and stronger x and y axis lines. Another choice was to eliminate the key legend by using the option
[legend, false]. If you want a key legend to appear when plotting multiple functions, you should remove that
option from the code and reload qplot.mac.
19
2.1.9
1.5
0.5
-0.5
-3
-2
-1
To check for the existence of a file, you can use the standard Maxima function file_search or the mfiles package function
probe_file (the latter is experimental and seems to work in a M.S. Windows version of Maxima). In the following, the file
ztemp.txt exists in the current working directory (c:/work2/), and the file ytemp.txt does not exist in this work folder.
Both functions return false when the file is not found. You need to supply the full file name including any extension, as a string.
The XMaxima output shown here uses display2d:true (the default). If you use the non-default setting
(display2d:false), strings will appear surrounded by double-quotes, but unpleasant backslash escape characters \ will appear
in the output.
20
In the following, we have not yet loaded mfiles.mac.
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
(%o8)
(%i9)
(%o9)
file_search ("ztemp.txt");
c:/work2/ztemp.txt
probe_file ("ztemp.txt");
probe_file(ztemp.txt)
load(mfiles);
c:/work2/mfiles.mac
probe_file ("ztemp.txt");
false
probe_file ("c:/work2/ztemp.txt");
c:/work2/ztemp.txt
myf : mkp("ztemp.txt");
c:/work2/ztemp.txt
probe_file (myf);
c:/work2/ztemp.txt
file_search ("ztemp");
false
file_search ("ytemp.txt");
false
Although the core Maxima function file_search does not need the complete path (due to our maxima.init file
contents), our homemade functions, such as probe_file do need a complete path, due to recent changes in Maxima.
To ease the pain of typing the full path, you can use a function which we call mkp (make path) which we define in our
maxima.init.mac file, whose contents are:
/* this is c:\Documents and Settings\Edwin Woollett\maxima\maxima-init.mac */
maxima_userdir: "c:/work2" $
maxima_tempdir : "c:/work2"$
file_search_maxima : append(["c:/work2/###.{mac,mc}"],file_search_maxima )$
file_search_lisp : append(["c:/work2/###.lisp"],file_search_lisp )$
bpath : "c:/work2/"$
mkp (_fname) := sconcat (bpath,_fname)$
We have used this function, mkp above, to get probe_file to work. The string processing function sconcat creates
a new string from two given strings (string concatenation):
(%i10) display2d:false$
(%i11) sconcat("a bc","xy z");
(%o11) "a bcxy z"
Note that we defined (in our maxima-init.mac file) a global variable bpath (base of path or beginning of path) instead of using the global variable maxima_userdir. This makes it more convenient for the user to redefine bpath
on the fly (inside a maxima session) instead of opening and editing maxima-init.mac, and restarting Maxima to
have the changes take effect.
We see that file_search is easier to use than probe_file.
2.2.2
The mfiles.mac package functions ls and dir accept the use of a wildcard pathname. Both functions are experimental and are not guaranteed to work with Maxima engines compiled with a Lisp version different from GCL (Gnu Common
Lisp) (which is the Lisp version used for the Windows binary used by the author).
21
Again, you must use the full path, and can make use of the mkp function as in the above examples. The last examples
below refer to a folder different than the working folder c:/work2/.
(%i12)
(%o12)
(%i13)
(%o13)
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
(%i17)
(%o17)
2.2.3
ls(mkp("*temp.txt"));
[c:/work2/REPLACETEMP.TXT, c:/work2/temp.txt, c:/work2/ztemp.txt]
ls("c:/work2/*temp.txt");
[c:/work2/REPLACETEMP.TXT, c:/work2/temp.txt, c:/work2/ztemp.txt]
dir(mkp("*temp.txt"));
[REPLACETEMP.TXT, temp.txt, ztemp.txt]
dir("c:/work2/*temp.txt");
[REPLACETEMP.TXT, temp.txt, ztemp.txt]
ls ("c:/work3/dirac.*");
[c:/work3/dirac.mac, c:/work3/dirac.tex]
dir ("c:/work3/dirac.*");
[dirac.mac, dirac.tex]
The text file lisp1w.txt is a file with Windows line ending control characters which has three lines of text and no blank
lines.
(%i18) file_search("lisp1w.txt");
(%o18)
c:/work2/lisp1w.txt
(%i19) file_lines("lisp1w.txt");
openr: file does not exist: lisp1w.txt
#0: file_lines(fnm=lisp1w.txt)(mfiles.mac line 637)
-- an error. To debug this try: debugmode(true);
(%i20) file_lines(mkp("lisp1w.txt"));
(%o20)
[3, 3]
(%i21) file_lines("c:/work2/lisp1w.txt");
(%o21)
[3, 3]
myf:mkp("lisp1w.txt");
c:/work2/lisp1w.txt
ftype(myf);
windows
file_length(myf);
131
file_info(myf);
[3, 3, windows, 131]
The function ftype (file type) returns either windows, unix, or mac depending on the nature of the end of line
chars. The function file_length returns the number of characters (chars) in the file, including the end of line
chars. The function file_info combines the line number info, the file type, and the number of characters into one list.
2.2.4
For a small file the packge function print_file(file) is useful. For a larger file
print_lines(file,start,end) is useful.
(%i26) print_file (myf)$
Lisp (or LISP) is a family of computer programming
languages with a long history and a distinctive, fully
parenthesized syntax.
(%i27) myf : mkp("lisp2.txt");
(%o27)
c:/work2/lisp2.txt
22
(%i28) file_info(myf);
(%o28)
[8, 8, windows, 504]
(%i29) print_lines(myf,3,5)$
parenthesized syntax. Originally specified in 1958, Lisp is
the second-oldest high-level programming language in
widespread use today; only Fortran is older (by one year).
2.2.5
The mfiles.mac package function rename_file (oldname,newname) is an experimental function which works
as follows in a Windows version of Maxima (again we must use the complete path):
(%i30)
(%o30)
(%i31)
(%o31)
(%i32)
(%o32)
(%i33)
(%o33)
(%i34)
(%o34)
2.2.6
file_search("foo1.txt");
false
file_search("bar1.txt");
c:/work2/bar1.txt
rename_file(mkp("bar1.txt"),mkp("foo1.txt"));
c:/work2/foo1.txt
file_search("foo1.txt");
c:/work2/foo1.txt
file_search("bar1.txt");
false
The mfiles.mac package function delete_file (filename) does what its name implies:
(%i35) file_search("bar2.txt");
(%o35)
c:/work2/bar2.txt
(%i36) delete_file(mkp("bar2.txt"));
(%o36)
done
(%i37) file_search("bar2.txt");
(%o37)
false
2.2.7
The mfiles.mac package function copy_file(fsource,fdest) will preserve the file type, but will not warn
you if you are over-writing a previous file name.
(%i38)
(%o38)
(%i39)
(%o39)
(%i40)
(%o40)
(%i41)
(%o41)
2.2.8
file_search("foo2.txt");
false
file_info(mkp("foo1.txt"));
[3, 3, windows, 59]
copy_file(mkp("foo1.txt"),mkp("foo2.txt"));
c:/work2/foo2.txt
file_info(mkp("foo2.txt"));
[3, 3, windows, 59]
Here, file type refers to the text file types unix, windows, and mac, each distinguised by the use of different conventions in indicating the end of a text file line.
Syntax: file_convert(file, newtype) or
file_convert (oldfile, newfile,newtype)
The acceptable values of newtype are windows, unix, and mac.
23
For example, we can change a unix file to a windows file using file_convert(f,windows) which replaces the previous file, or we can change a unix file to a windows file with a new name using file_convert(fold,fnew,windows).
It is easy to check the end of line characters using the Notepad2 View menu. Notepad2 also easily lets you change the end
of line characters, so writing Maxima code for this task is somewhat unneeded, though instructive as a coding challenge.
(%i42) file_search("bar1.txt");
(%o42)
c:/work2/bar1.txt
(%i43) file_search("bar2.txt");
(%o43)
c:/work2/bar2.txt
(%i44) print_file(mkp("bar1.txt"))$
This is line one.
This is line two.
This is line three.
(%i45) file_info(mkp("bar1.txt"));
(%o45)
[3, 3, windows, 59]
(%i46) file_convert(mkp("bar1.txt"),mkp("bar11u.txt"),unix);
(%o46)
c:/work2/bar11u.txt
(%i47) file_info(mkp("bar11u.txt"));
(%o47)
[3, 3, unix, 56]
(%i48) print_file(mkp("bar2.txt"));
This is line one.
This is line two.
This is line three.
(%o48)
c:/work2/bar2.txt
(%i49) file_info(mkp("bar2.txt"));
(%o49)
[3, 3, windows, 59]
(%i50) file_convert(mkp("bar2.txt"),mac);
(%o50)
c:/work2/bar2.txt
(%i51) file_info(mkp("bar2.txt"));
(%o51)
[3, 3, mac, 56]
(%i52) print_file(mkp("bar2.txt"));
This is line one.
This is line two.
This is line three.
(%o52)
c:/work2/bar2.txt
2.2.9
Four paragraphs of the Lisp entry from part of Paul Grahams web site were copied into a text file ztemp.txt. In
Notepad2, each paragraph was one long line.
Inside Maxima, we then used the mfiles package function pbreak_lines (file,nmax) to break the lines (at a
space) and print the results to the console screen of Xmaxima.
(%i53) file_info(mkp("ztemp.txt"));
(%o53)
[7, 13, windows, 1082]
(%i54) print_lines(mkp("ztemp.txt"),1,1);
6. Programs composed of expressions. Lisp programs are trees ...[continues]
(%o54)
c:/work2/ztemp.txt
(%i55) pbreak_lines(mkp("ztemp.txt"),60)$
6. Programs composed of expressions. Lisp programs are
trees of expressions, each of which returns a value. (In
some Lisps expressions can return multiple values.) This is
in contrast to Fortran and most succeeding languages, which
distinguish between expressions and statements.
It was natural to have this distinction in Fortran because
(not surprisingly in a language where the input format was
punched cards) the language was line-oriented. You could
not nest statements. And so while you needed expressions
24
Once the line breaking text appears on the console screen, one can copy and paste into a text file for further use.
It is simpler to use the function pbreak() which has nmax = 72 hardwired in the code, as well as the name
"ztemp.txt"; this could be used in the above example as pbreak(), and is easy to use since you dont have to type
either the text file name or the value of nmax.
The package function pbreak() uses the current definition of bpath and mkp, as well as the file name "ztemp.txt".
(%i56) pbreak();
6. Programs composed of expressions. Lisp programs are trees of
expressions, each of which returns a value. (In some Lisps expressions
can return multiple values.) This is in contrast to Fortran and most
succeeding languages, which distinguish between expressions and
statements.
It was natural to have this distinction in Fortran because (not
surprisingly in a language where the input format was punched cards)
the language was line-oriented. You could not nest statements. And so
while you needed expressions for math to work, there was no point in
making anything else return a value, because there could not be
anything waiting for it.
This limitation went away with the arrival of block-structured
languages, but by then it was too late. The distinction between
expressions and statements was entrenched. It spread from Fortran into
Algol and thence to both their descendants.
When a language is made entirely of expressions, you can compose
expressions however you want. You can say either (using Arc syntax)
(if foo (= x 1) (= x 2))
or
(= x (if foo 1 2))
(%o56)
done
25
Alternatively, one can employ the mfiles package function break_file_lines (fold,fnew,nmax) to dump
the folded lines into created file fnew.
(%i57) break_file_lines (mkp("ztemp.txt"),mkp("ztemp1.txt"),72);
(%o57)
c:/work2/ztemp1.txt
(%i58) print_lines(mkp("ztemp1.txt"),1,2);
6. Programs composed of expressions. Lisp programs are trees of
expressions, each of which returns a value. (In some Lisps expressions
(%o58)
c:/work2/ztemp1.txt
(%i59) file_info(mkp("ztemp.txt"));
(%o59)
[7, 13, windows, 1082]
(%i60) file_info(mkp("ztemp1.txt"));
(%o60)
[20, 26, windows, 1095]
2.2.10
26
We next demonstrate all three possible syntax forms with a purely text file text1.txt.
(%i65) file_info (mkp("text1.txt"));
(%o65)
[5, 5, windows, 152]
(%i66) print_file (mkp("text1.txt"))$
is this line one? Yes, this is line one.
This might be line two.
Here is line three.
I insist that this be line four.
This is line five, isnt it?
(%i67) search_file (mkp("text1.txt"),"is")$
c:/work2/text1.txt
1 is this line one? Yes, this is line one.
3 Here is line three.
5 This is line five, isnt it?
(%i68) search_file (mkp("text1.txt"),"is",word)$
c:/work2/text1.txt
1 is this line one? Yes, this is line one.
3 Here is line three.
5 This is line five, isnt it?
(%i69) search_file (mkp("text1.txt"),"is",all)$
c:/work2/text1.txt
1 is this line one? Yes, this is line one.
2 This might be line two.
3 Here is line three.
4 I insist that this be line four.
5 This is line five, isnt it?
2.2.11
The most general syntax is search_mfiles (file or path,string,options...) in which the options
recognised are word, all, cs, ic, used in the same way as described above for search_file. The simplest
syntax is search_mfiles (file or path,string) which defaults to case sensitive (cs) and isolated word
(word) as options. An example of over-riding the default behavior (cs and word) would be
search_mfiles (file or path, string,ic, all) and the options args can be in either order.
First an example of searching one file in the working directory.
(%i1) load(mfiles);
(%o1)
c:/work2/mfiles.mac
(%i2) print_file(mkp("text1.txt"))$
is this line one? Yes, this is line one.
This might be line two.
Here is line three.
I insist that this be line four.
This is line five, isnt it?
(%i3) search_mfiles(mkp("text1.txt"),"is")$
c:/work2/text1.txt
1 is this line one? Yes, this is line one.
3 Here is line three.
5 This is line five, isnt it?
(%i4) search_mfiles(mkp("text1.txt"),"Is")$
(%i5)
27
Next we use a wildcard type file name for a search in the working directory.
(%i5) search_mfiles(mkp("ndata*.dat"),"is")$
c:/work2/ndata1.dat
1 The calculation of the effective cross section is much simplified if only
3 those collisions are considered for which the impact parameter is large, so
5 that the field U is weak and the angles of deflection are small. The
Next we return to a search of the single file text1.txt, but look for lines containing the string "is" whether or not it
is an instance of an isolated word.
(%i6) search_mfiles(mkp("text1.txt"),"is",all)$
c:/work2/text1.txt
1 is this line one? Yes, this is line one.
2 This might be line two.
3 Here is line three.
4 I insist that this be line four.
5 This is line five, isnt it?
We now use search_mfiles to look for a text string in a file atext1.txt which is not in the current working
directory.
(%i1) load(mfiles);
(%o1)
c:/work2/mfiles.mac
(%i2) search_mfiles ("c:/work2/temp1/atext1.txt","is");
c:/work2/temp1/atext1.txt
2 Is this line two? Yes, this is line two.
6 This is line six, Isnt it?
(%o2)
done
If you want to search all files in the folder c:/work2/temp1, you use the syntax:
(%i3) search_mfiles ("c:/work2/temp1/","is")$
c:/work2/temp1/atext1.txt
2 Is this line two? Yes, this is line two.
6 This is line six, Isnt it?
c:/work2/temp1/atext2.txt
2 Is this line two? Yes, this is line two.
6 This is line six, Isnt it?
c:/work2/temp1/calc1news.txt
9 The organization of chapter six is then:
96 The Maxima output is the list of the vector curl components in the
98
a reminder to the user of what the current coordinate system is
102 Thus the syntax is based on lists and is similar to (although better
105 There is a separate function to change the current coordinate system.
112
plotderiv(..) which is useful for "automating" the plotting
c:/work2/temp1/ndata1.dat
1 The calculation of the effective cross section is much simplified if only
3 those collisions are considered for which the impact parameter is large, so
5 that the field U is weak and the angles of deflection are small. The
c:/work2/temp1/stavros-tricks.txt
34 Not a bug, but Maxima doesnt know that the beta function is symmetric:
28
c:/work2/temp1/text1.txt
1 is this line one? Yes, this is line one.
3 Here is line three.
5 This is line five, isnt it?
c:/work2/temp1/trigsimplification.txt
13 (1) Is there a Maxima command that indicates whether expr is a product of
76 > (1) Is there a Maxima command that indicates whether expr is a product of
91 Well, that is inherent in their definition. Trigreduce replaces all
94 is sin(x)*cos(x), since the individual terms are not products of trigs.
95 There is no built-in function which tries to find the smallest expression,
151 is better. If the user wants to expand the contents of sin to discover
153 is right that Maxima avoids potentially very expensive operations in
c:/work2/temp1/wu-d.txt
1 As a dedicated windows xp user who is delighted to have windows binaries
3 all who are considering windows use that there is no problem with keeping previous
2.2.12
The simplest syntax ftext_replace(file,sold,snew) replaces distinct substrings sold (separate words) by
snew.
The four arg syntax ftext_replace(file,sold,snew,word) does exactly the same thing.
The four arg syntax ftext_replace(file,sold,snew,all) instead replaces all substrings sold by snew,
whether or not they are distinct words.
In all cases, the text file type (unix, windows, or mac) is preserved.
The package function ftext_replace calls the package function
replace_file_text (fsource, fdest, sold,snew, optional-mode) which allows the replacement
to occur in a newly created file with a name fdest.
(%i4) file_info(mkp("text1w.txt"));
(%o4)
[5, 5, windows, 152]
(%i5) print_file(mkp("text1w.txt"));
is this line one? Yes, this is line one.
This might be line two.
Here is line three.
I insist that this be line four.
This is line five, isnt it?
(%o5)
c:/work2/text1w.txt
(%i6) ftext_replace(mkp("text1w.txt"),"is","was");
(%o6)
c:/work2/text1w.txt
(%i7) print_file(mkp("text1w.txt"));
was this line one? Yes, this was line one.
This might be line two.
Here was line three.
I insist that this be line four.
This was line five, isnt it?
(%o7)
c:/work2/text1w.txt
(%i8) file_info(mkp("text1w.txt"));
(%o8)
[5, 5, windows, 156]
(%i9) ftext_replace(mkp("text1w.txt"),"was","is");
(%o9)
c:/work2/text1w.txt
29
(%i10) print_file(mkp("text1w.txt"));
is this line one? Yes, this is line one.
This might be line two.
Here is line three.
I insist that this be line four.
This is line five, isnt it?
(%o10)
c:/work2/text1w.txt
2.2.13
The package function reply_to (name-string) reads an email message (or part of an email message) which has
been dumped into the current working directory file called ztemp.txt (the name chosen so the file is easy to find) and
writes a version of that file to the console screen with a supplied name prefixing each line, suitable for a copy/paste into a
reply email message.
It will be obvious if the message lines need breaking. If so, then use pbreak(), which will place the broken line message on the Xmaxima console screen, which can be copied and pasted over the original contents of ztemp.txt.
Once you are satisfied with the appearance of the message in ztemp.txt, use reply_to("Ray") for example, which
will print out on the console screen the email message with each line prefixed by "Ray". This output can then be copied
from the Xmaxima screen and pasted into the email message being designed as a reply.
(%i11) reply_to("");
>Could you file a bug report on this? I know about some of these issues
>and am working on them (slowly). The basic parts work, but the corner
>cases need more work (especically since my approach fails in some cases
>where the original gave correct answers).
>
(%o11)
done
or
(%i12) reply_to(" ray")$
ray>Could you file a bug report on this? I know about some of these issues
ray>and am working on them (slowly). The basic parts work, but the corner
ray>cases need more work (especically since my approach fails in some cases
ray>where the original gave correct answers).
ray>
2.2.14
An important advantage of read_data is the ability to work correctly with all three types of text files (unix, windows,
and mac).
Our first example data file has the data items separated by commas on the first line and by spaces on the second line. The
data items are a mixture of integers, rational numbers, strings, and floating point numbers. None of the strings contain
spaces.
The function read_data places the items of each line in the data file into a separate list.
(%i13) print_file(mkp("ndata2w.dat"))$
2 , 4.8, -3/4, "xyz", -2.8e-9
3 22.2 7/8 "abc" 4.4e10
30
(%i14) read_data(mkp("ndata2w.dat"));
3
(%o14) [[2, 4.8, - -, xyz, - 2.7999999999999998E-9],
4
7
[3, 22.2, -, abc, 4.4E+10]]
8
(%i15)
(%i16)
(%o16)
(%i17)
(%i18)
(%o18)
display2d:false$
read_data(mkp("ndata2w.dat"));
[[2,4.8,-3/4,"xyz",-2.7999999999999998E-9],[3,22.2,7/8,"abc",4.4E+10]]
fpprintprec:8$
read_data(mkp("ndata2w.dat"));
[[2,4.8,-3/4,"xyz",-2.8E-9],[3,22.2,7/8,"abc",4.4E+10]]
This simplest syntax mode of read_data does not care where the commas and spaces are, they can be randomly used
as data item separators, and the data is read into lists correctly:
(%i19) print_file(mkp("ndata2wa.dat"))$
2 , 4.8 -3/4, "xyz" -2.8e-9
3 22.2, 7/8 "abc", 4.4e10
(%i20) read_data(mkp("ndata2wa.dat"));
(%o20) [[2,4.8,-3/4,"xyz",-2.8E-9],[3,22.2,7/8,"abc",4.4E+10]]
Next is a case in which the data item separator is consistently a semicolon ;. In such a case we must include as a second
argument to read_data the string ";".
(%i21) print_file(mkp("ndata3w.dat"))$
2.0; -3/7; (x:1,y:2,x+y); block([fpprec:24],bfloat(%pi)); foo
(%i22) read_data(mkp("ndata3w.dat"),";");
(%o22) [[2.0,-3/7,(x:1,y:2,y+x),block([fpprec:24],bfloat(%pi)),foo]]
(If some of the data items include semicolons, then you would not want to use semicolons as data item separators; rather
you might choose a dollar sign $ as the separator, and so indicate as the second argument.)
Our next example is a data file which includes some strings which include spaces inside the strings. The data file should
use commas as data item separators, and the correct syntax to read the data is read_data(file,",").
(%i23) print_file(mkp("ndata6.dat"));
1, 2/3, 3.4, 2.3e9, "file ndata6.dat"
"line two" , -3/4 , 6 , -4.8e-7 , 5.5
7/13, "hi there", 8, 3.3e4, -7.3
4,-3/9,"Jkl", 44.6, 9.9e-6
(%o23) "c:/work2/ndata6.dat"
(%i24) read_data(mkp("ndata6.dat"),",");
(%o24) [[1,2/3,3.4,2.3E+9,"file ndata6.dat"],["line two",-3/4,6,-4.8E-7,5.5],
[7/13,"hi there",8,33000.0,-7.3],[4,-1/3,"Jkl",44.6,9.9E-6]]
The package function read_data ignores blank lines in the data file (as it should):
(%i25) print_file(mkp("ndata10w.dat"))$
2 4.8 -3/4 "xyz" -2.8e-9
2
4.8
-3/4
"xyz"
-2.8e-9
4.8
-3/4
"xyz"
-2.8e-9
(%i26) read_data(mkp("ndata10w.dat"));
(%o26) [[2,4.8,-3/4,"xyz",-2.8E-9],[2,4.8,-3/4,"xyz",-2.8E-9],
[2,4.8,-3/4,"xyz",-2.8E-9]]
(%i27) file_info (mkp("ndata10w.dat"));
(%o27) [3,6,windows,98]
31
2.2.15
The package function read_text(path) preserves blank lines in the source file, and returns a list of strings, one for
each physical line in the source file.
(%i28) print_file(mkp("ndata1.dat"))$
The calculation of the effective cross section is much simplified if only
those collisions are considered for which the impact parameter is large, so
that the field U is weak and the angles of deflection are small. The
calculation can be carried out in the laboratory system, and the center
of mass frame need not be used.
(%i29) read_text(mkp("ndata1.dat"));
(%o29) ["The calculation of the effective cross section is much simplified if only",
"",
"those collisions are considered for which the impact parameter is large, so",
"",
"that the field U is weak and the angles of deflection are small. The",
"",
"calculation can be carried out in the laboratory system, and the center",
"","of mass frame need not be used."]
2.2.16
Writing Data to a Data File One Line at a Time Using with stdout
The core Maxima function with_stdout can be used to write loop results to a file instead of to the screen. This can be
used to create a separate data file as a byproduct of your Maxima work. The function has the syntax
with_stdout (file,expr1,expr2,...) and writes any output generated with print, display, or grind
(for example) to the indicated file, overwriting any pre-existing file, and creating a unix type file.
(%i30) with_stdout (mkp("tmp.out"),
for i thru 10 do
print (i,",",i2,",",i3))$
(%i31) print_file (mkp("tmp.out"))$
1 , 1 , 1
2 , 4 , 8
3 , 9 , 27
4 , 16 , 64
5 , 25 , 125
6 , 36 , 216
7 , 49 , 343
8 , 64 , 512
9 , 81 , 729
10 , 100 , 1000
(%i32) read_data (mkp("tmp.out"));
(%o32) [[1,1,1],[2,4,8],[3,9,27],[4,16,64],[5,25,125],[6,36,216],[7,49,343],
[8,64,512],[9,81,729],[10,100,1000]]
(%i33) file_info (mkp("tmp.out"));
(%o33) [10,10,unix,134]
Notice that if you dont provide the full path to your work directory with the file name (with the Maxima function
with_stdout), the file will be created in the ../bin/ folder of Maxima.
32
2.2.17
The core Maxima function write_data can be used to write the contents of a nested list to a named file, writing one line for each sublist, overwriting the contents of any pre-existing file of that name, creating a unix type file
with space separator as the default. The simplest syntax, write_data (list, filename) produces the default
space separation of the sublist items. You can get comma separation or semicolon separation by using respectively
write_data (list,filename,comma) or write_data (list,filename,semicolon).
Note again that you need to supply the full path as well as the file name, or else the file will be created by write_data
in .../bin/.
(This same function can also be used to write a Maxima matrix object to a data file.)
(%i34)
(%i35)
(%i36)
(%o36)
(%i37)
0 2
1 3
2 4
(%i38)
(%o38)
(%i39)
(%i40)
0,2
1,3
2,4
(%i41)
(%o41)
(%i42)
(%i43)
0;2
1;3
2;4
dataL : [[0,2],[1,3],[2,4]]$
write_data(dataL,mkp("tmp.out"))$
file_search("tmp.out");
"c:/work2/tmp.out"
print_file(mkp("tmp.out"))$
file_info(mkp("tmp.out"));
[3,3,unix,12]
write_data(dataL,mkp("tmp.out"),comma)$
print_file(mkp("tmp.out"))$
file_info(mkp("tmp.out"));
[3,3,unix,12]
write_data(dataL,mkp("tmp.out"),semicolon)$
print_file(mkp("tmp.out"))$
Here is a simple example taken from a question from the Maxima mailing list. Suppose you compute the expression
(1 - z)/(1 + z) for a number of values of z, and you want to place the numbers z , f(z) in a data file for later
use.
The easiest way to do this in Maxima is to create a list of sublists, with each sublist being a row in your new data file. You
can then use the Maxima function write_data, which has the syntax: write_data ( datalist, filename ).
Lets keep the example really simple and just use five integral values of z, starting with an empty list we will call dataL.
(The final L is useful (but not necessary) to remind us that it stands for a list.)
(%i44) dataL : []$
(%i45) for x thru 5 do (
px : subst (x,z, (1-z)/(1+z)),
dataL : cons ( [x, px], dataL ))$
(%i46) dataL;
(%o46) [[5,-2/3],[4,-3/5],[3,-1/2],[2,-1/3],[1,0]]
(%i47) dataL : reverse (dataL);
(%o47) [[1,0],[2,-1/3],[3,-1/2],[4,-3/5],[5,-2/3]]
33
(%i48)
(%i49)
1 0
2 -1/3
3 -1/2
4 -3/5
5 -2/3
(%i50)
(%o50)
(%i51)
(%o51)
read_data (mkp("mydata1.dat"));
[[1,0],[2,-1/3],[3,-1/2],[4,-3/5],[5,-2/3]]
file_info (mkp("mydata1.dat"));
[5,5,unix,32]
If you open the unix text file mydata1.dat using the older version of the Windows text file application Notepad, you
may only see one line, which looks like:
1 02 -1/33 -1/24 -3/55 -2/3
which occurs because Maxima creates text files having Unix style line endings which older native Windows applications
dont recognise.
In order to see the two columns of numbers (using a text editor), you should use the freely available Windows text editor
Notepad2. (Just Google it.) Notepad2 recognises unix, mac and windows line ending control characters, and in fact has a
signal (LF for unix) at the bottom of the screen which tells you what the line ending control characters are.
The alternative choice provided by the standard Maxima system to created a nested list from a data file is the function
read_nested_list. This is not as good a choice as our package function read_data, as is shown here:
(%i52)
(%o52)
(%i53)
(%i54)
(%o54)
read_nested_list (mkp("mydata1.dat"));
[[1,0],[2,-1,\/,3],[3,-1,\/,2],[4,-3,\/,5],[5,-2,\/,3]]
display2d:true$
read_nested_list (mkp("mydata1.dat"));
[[1, 0], [2, - 1, /, 3], [3, - 1, /, 2], [4, - 3, /, 5],
[5, - 2, /, 3]]
Suppose we are given a list of [x,y] pairs which are thought to be roughly described by the relation y = a*xb + c,
where the three parameters are all of order 1. We can use the data of [x,y] pairs to find the best values of the unknown
parameters [a, b, c], such that the data is described by the equation y = a*xb + c (a three parameter fit to the
data).
We are using one of the Manual examples for lsquares estimates.
(%i1)
(%i2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%i6)
34
Note that we must use load (lsquares); to use this method. We can now make a plot of both the discrete data
points and the least squares fit to those four data points.
(%i8) plot2d ([myfit,[discrete,dataL]],[x,0,5],
[style,[lines,5],[points,4,2,1]],
[legend,"myfit", "data"],
[gnuplot_preamble,"set key bottom;"])$
-0.5
0
2.3.2
in which the data-variable-list assigns a variable name to the corresponding column of the data-matrix,
and the fit-eqn is an equation which is a relation among the data variable symbols and the equation parameters
which appear in param-list. The function returns the best fit values of the equation parameters in the form
[ [p1 = p1val, p2 = p2val, ...] ].
In the example above, the data variable list was [x, y] and the parameter list was [a, b, c].
If an exact solution cannot be found, a numerical approximation is attempted using lbfgs, in which case, all the elements
of the data matrix should be numbers numberp(x) -> true. This means that %pi and %e, for example, should
be converted to explicit numbers before use of this method.
(%i1) expr : 2*%pi + 3*exp(-4);
- 4
(%o1)
(%i2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
2 %pi + 3 %e
listconstvars:true$
listofvars(expr);
[%e, %pi]
map(numberp,%);
[false, false]
fullmap(numberp,expr);
(%o5)
(%i6) float(expr);
(%o6)
(%i7) numberp(%);
(%o7)
true
false
true + false true
6.338132223845789
true
35
Optional arguments to lsquares estimates are (in any order)
initial = [p10, p20,...], iprint = [n, m], tol = search-tolerance
The list [p10, p20, ...] is the optional list of initial values of the equation parameters, and without including your
own guess for starting values this list defaults (in the code) to [1, 1, ...].
The first integer n in the iprint list controls how often progress messages are printed to the screen. The default is
n = 1 which causes a new progress message printout each iteration of the search method. Using n = -1 surpresses all
progress messages. Using n = 5 allows one progress message every five iterations.
The second integer m in the iprint list controls the verbosity, with m = 0 giving minimum information and m = 3
giving maximum information.
The option iprint = [-1,0] will hide the details of the search process.
The default value of the search-tolerance is 1e-3, so by using the option tol = 1e-8 you might find a more
accurate solution.
Many examples of the use of the lsquares package are found in the file lsquares.mac, which is found in the
...share/contrib folder. You can also see great examples of efficient programming in the Maxima language in
that file.
2.3.3
Newtons law of cooling (only approximate and not a law) assumes the rate of decrease of temperature (celsius degrees
per minute) is proportional to the instantaneous difference between the temperature T(t) of the coffee in the cup and the
surrounding ambient temperature Ts , the latter being treated as a constant. If we use the symbol r for the rate constant
of proportionality, we then assume the cooling of the coffee obeys the first order differential equation
dT
= r (T(t) Ts )
dt
(2.1)
Since T has dimension degrees Celsius, and t has dimension minute, the dimension of the rate constant r must be 1/min.
(This attempt to employ a rough mathematical model which can be used for the cooling of a cup of coffee avoids a
bottom-up approach to the problem, which would require mathematical descriptions of the four distinct physical mechanisms which contribute to the decrease of thermal energy in the system hot coffee plus cup to the surroundings: thermal
radiation (net electromagnetic radiation flux, approximately black body ) energy transport across the surface of the liquid
and cup, collisional heat conduction due to the presence of the surrounding air molecules, convective energy transport due
to local air temperature rise, and finally evaporation which is the escape of the fastest coffee molecules which are able to
escape the binding surface forces at the liquid surface. If the temperature difference between the coffee and the ambient
surroundings is not too large, experiment shows that the simple relation above is roughly true.)
This differential equation is easy to solve by hand , since we can write
d (T Ts )
dy
dT
=
=
dt
dt
dt
(2.2)
and then divide both sides by y = (T Ts ), multiply both sides by d t, and use d y/y = d ln(y) and finally integrate
both sides over corresponding intervals to get ln(y) ln(y0 ) = ln(y/y0 ) = r t, where y0 = T(0) Ts involves
the initial temperature at t = 0. Since
eln(A) = A,
(2.3)
36
by equating the exponential of the left side to that of the right side, we get
T(t) = Ts + (T(0) Ts ) er t .
(2.4)
Using ode2, ic1, expand, and collectterms, we can also use Maxima just for fun:
(%i1) de : diff(T,t) + r*(T - Ts);
dT
(%o1)
-- + r (T - Ts)
dt
(%i2) gsoln : ode2(de,T,t);
- r t
r t
(%o2)
T = %e
(%e
Ts + %c)
(%i3) de, gsoln, diff, ratsimp;
(%o3)
0
(%i4) ic1 (gsoln, t = 0, T = T0);
- r t
r t
(%o4)
T = %e
(T0 + (%e
- 1) Ts)
(%i5) expand (%);
- r t
- r t
(%o5)
T = %e
T0 - %e
Ts + Ts
(%i6) Tcup : collectterms ( rhs(%), exp(-r*t) );
- r t
(%o6)
%e
(T0 - Ts) + Ts
(%i7) Tcup, t = 0;
(%o7)
T0
We arrive at the same solution as found by hand. We have checked the particular solution for the initial condition and
checked that our original differential equation is satisfied by the general solution.
2.3.4
Lets take some real world data for this problem (p. 21, An Introduction to Computer Simulation Methods, 2nd ed.,
Harvey Gould and Jan Tobochnik, Addison-Wesley, 1996) which is in a data file c:\work2\coffee.dat on the authors
Windows XP computer (data file available with this chapter on the authors webpage).
This file contains three columns of tab separated numbers, column one being the elapsed time in minutes, column two
is the Celsius temperature of the system glass plus coffee for black coffee, and column three is the Celsius temperature
for the system glass plus creamed coffee. The glass-coffee temperature was recorded with an estimated accuracy of
0.1 C. The ambient temperature of the surroundings was 17 C. The function read_data automatically replaces tabs
(ascii(9)) in the data by spaces (ascii(32)) as each line is read in.
We need to remind the reader that we are using a function mkp to create a complete path to a file name. This function
was discussed at the beginning of the section on file manipulation methods. For convenience, we repeat some of that
discussion here:
To ease the pain of typing the full path, you can use a function which we call mkp (make path) which we define in our
maxima.init.mac file, whose contents are:
/* this is c:\Documents and Settings\Edwin Woollett\maxima\maxima-init.mac */
maxima_userdir: "c:/work2" $
maxima_tempdir : "c:/work2"$
file_search_maxima : append(["c:/work2/###.{mac,mc}"],file_search_maxima )$
file_search_lisp : append(["c:/work2/###.lisp"],file_search_lisp )$
bpath : "c:/work2/"$
mkp (_fname) := sconcat (bpath,_fname)$
37
We will use this function, mkp, below for example with print_file and read_data. The string processing function
sconcat creates a new string from two given strings (string concatenation):
(%i8) display2d:false$
(%i9) sconcat("a bc","xy z");
(%o9) "a bcxy z"
Note that we used a global variable bpath (base of path or beginning of path) instead of the global variable
maxima_userdir. This makes it more convenient for the user to redefine bpath on the fly instead of opening
and editing maxima-init.mac, and restarting Maxima to have the changes take effect.
(%i10)
(%o10)
(%i11)
(%o11)
(%i12)
0
2
4
6
8
10
12
14
16
18
20
22
24
26
28
30
32
34
36
38
40
42
44
file_search("coffee.dat");
c:/work2/coffee.dat
(display2d:false,load(mfiles));
"c:/work2/mfiles.mac"
print_file(mkp("coffee.dat"))$
82.3
68.8
78.5
64.8
74.3
62.1
70.7
59.9
67.6
57.7
65.0
55.9
62.5
53.9
60.1
52.3
58.1
50.8
56.1
49.5
54.3
48.1
52.8
46.8
51.2
45.9
49.9
44.8
48.6
43.7
47.2
42.6
46.1
41.7
45.0
40.8
43.9
39.9
43.0
39.3
41.9
38.6
41.0
37.7
40.1
37.0
We now use read_data which will create a list of sublists, one sublist per row.
(%i13) fpprintprec:6$
(%i14) cdata : read_data(mkp("coffee.dat"));
(%o14) [[0,82.3,68.8],[2,78.5,64.8],[4,74.3,62.1],[6,70.7,59.9],[8,67.6,57.7],
[10,65.0,55.9],[12,62.5,53.9],[14,60.1,52.3],[16,58.1,50.8],
[18,56.1,49.5],[20,54.3,48.1],[22,52.8,46.8],[24,51.2,45.9],
[26,49.9,44.8],[28,48.6,43.7],[30,47.2,42.6],[32,46.1,41.7],
[34,45.0,40.8],[36,43.9,39.9],[38,43.0,39.3],[40,41.9,38.6],
[42,41.0,37.7],[44,40.1,37.0]]
We now use makelist to create a (time, temperature) list based on the black coffee data and then based on the white
(creamed coffee) data.
(%i15) black_data : makelist( [first(cdata[i]),second(cdata[i])],
i,1,length(cdata));
(%o15) [[0,82.3],[2,78.5],[4,74.3],[6,70.7],[8,67.6],[10,65.0],[12,62.5],
[14,60.1],[16,58.1],[18,56.1],[20,54.3],[22,52.8],[24,51.2],[26,49.9],
[28,48.6],[30,47.2],[32,46.1],[34,45.0],[36,43.9],[38,43.0],[40,41.9],
[42,41.0],[44,40.1]]
38
2.3.5
We now use lsquares estimates to use a least squares fit with each of our data sets to our phenomenological model, that is
finding the best value of the cooling rate constant r that appears in Eq. (2.4). The function lsquares estimates(data matrix,
eqnvarlist,eqn,paramlist) is available after using load(lsquares).
To save space in this chapter we use display2d:false to surpress the default two dimensional display of a Maxima matrix
object.
(%i17) black_matrix : apply ( matrix, black_data);
(%o17) matrix([0,82.3],[2,78.5],[4,74.3],[6,70.7],[8,67.6],[10,65.0],[12,62.5],
[14,60.1],[16,58.1],[18,56.1],[20,54.3],[22,52.8],[24,51.2],
[26,49.9],[28,48.6],[30,47.2],[32,46.1],[34,45.0],[36,43.9],
[38,43.0],[40,41.9],[42,41.0],[44,40.1])
(%i18) white_matrix : apply ( matrix, white_data);
(%o18) matrix([0,68.8],[2,64.8],[4,62.1],[6,59.9],[8,57.7],[10,55.9],
[12,53.9],[14,52.3],[16,50.8],[18,49.5],[20,48.1],[22,46.8],
[24,45.9],[26,44.8],[28,43.7],[30,42.6],[32,41.7],[34,40.8],
[36,39.9],[38,39.3],[40,38.6],[42,37.7],[44,37.0])
We now load lsquares.mac and calculate the best fit values of the cooling rate constant r for both cases. For the black
coffee case, T0 = 82.3 deg C and Ts = 17 deg C and we surpress the units.
(%i19)
(%o19)
(%i20)
(%o20)
(%i21)
load(lsquares);
"C:/PROGRA1/MAXIMA1.1-G/share/maxima/5.25.1/share/contrib/lsquares.mac"
black_eqn : T = 17 + 65.3*exp(-r*t);
T = 65.3*%e-(r*t)+17
lsquares_estimates ( black_matrix, [t,T], black_eqn, [r],
iprint = [-1,0] );
(%o21) [[r = 0.02612]]
(%i22) black_fit : rhs ( black_eqn ), %;
(%o22) 65.3*%e-(0.02612*t)+17
Thus rwhite is roughly 0.024 min(-1), a slightly smaller value than for the black coffee ( which is reasonable since
a black body is a better radiator of thermal energy than a white surface).
39
A prudent check on mathematical reasonableness can be made by using, say, the two data points for t = 0 and t = 24 min
to solve for a rough value of r. For this rough check, the author concludes that rblack is roughly 0.027 min(-1)
and rwhite is roughly 0.024 min(-1).
We can now plot the temperature data against the best fit model curve, first for the black coffee case.
(%i26) plot2d( [ black_fit ,[discrete,black_data] ],
[t,0,50], [style, [lines,5], [points,2,2,6]],
[ylabel," "] ,
[xlabel," Black Coffee T(deg C) vs. t(min) with r = 0.026/min"],
[legend,"black fit","black data"] )$
black fit
black data
80
75
70
65
60
55
50
45
40
35
30
0
10
20
30
40
Black Coffee T(deg C) vs. t(min) with r = 0.026/min
50
white fit
white data
65
60
55
50
45
40
35
30
0
10
20
30
40
50
40
Cream at Start or Later?
Lets use the above approximate values for the cooling rate constants to find the fastest method to use to get the temperature
of hot coffee down to a drinkable temperature. Lets assume we start with a glass of very hot coffee, T0 = 90 C, and
want to compare two methods of getting the temperature down to 75 C, which we assume is low enough to start sipping.
We will assume that adding cream lowers the temperature of the coffee by 5 C for both options we explore. Option 1
(white option) is to immediately add cream and let the creamed coffee cool down from 85 C to 75 C. We first write
down a general expression as a function of T0 and r, and then substitute values appropriate to the white coffee cooldown.
(%i28)
(%o28)
(%i29)
(%o29)
(%i30)
(%o30)
T : 17 + (T0 -17)*exp(-r*t);
%e-(r*t)*(T0-17)+17
T1 : T, [T0 = 85, r = 0.02388];
68*%e-(0.02388*t)+17
t1 : find_root(T1 - 75,t,2,10);
6.661
The white option requires about 6.7 min for the coffee to be sippable.
Option 2 (the black option) lets the black coffee cool from 90 C to 80 C, and then adds cream, immediately getting the
temperature down from 80 C to 75 C
(%i31)
(%o31)
(%i32)
(%o32)
The black option (option 2) is the fastest method to cool the coffee, taking about 5.64 min which is about 61 sec less
than the white option 1.
Preface
COPYING AND DISTRIBUTION POLICY
This document is part of a series of notes titled
"Maxima by Example" and is made available
via the authors webpage http://www.csulb.edu/woollett/
to aid new users of the Maxima computer algebra system.
NON-PROFIT PRINTING AND DISTRIBUTION IS PERMITTED.
You may make copies of this document and distribute them
to others as long as you charge no more than the costs of printing.
These notes (with some modifications) will be published in book form
eventually via Lulu.com in an arrangement which will continue
to allow unlimited free download of the pdf files as well as the option
of ordering a low cost paperbound version of these notes.
Feedback from readers is the best way for this series of notes to become more helpful to new users of Maxima. All
comments and suggestions for improvements will be appreciated and carefully considered.
LOADING FILES
The defaults allow you to use the brief version load(fft) to load in the
Maxima file fft.lisp.
To load in your own file, such as qxxx.mac
using the brief version load(qxxx), you either need to place
qxxx.mac in one of the folders Maxima searches by default, or
else put a line like:
file_search_maxima : append(["c:/work2/###.{mac,mc}"],file_search_maxima )$
in your personal startup file maxima-init.mac (see later in this chapter
for more information about this).
Otherwise you need to provide a complete path in double quotes,
as in load("c:/work2/qxxx.mac"),
We always use the brief load version in our examples, which are generated
using the XMaxima graphics interface on a Windows XP computer, and copied
into a fancy verbatim environment in a latex file which uses the fancyvrb
and color packages.
desolve
gsoln : desolve(de, u(t) );
where de includes the equal sign (=)
and diff(u(t),t) and possibly u(t).
psoln : ratsubst(u0val,u(o),gsoln)
plotdf
plotdf ( dudt, [t,u], [trajectory_at, t0, u0],
[direction,forward], [t, tmin, tmax],
[u, umin, umax] )$
rk
points : rk ( dudt, u, u0, [t, t0, tlast, dt] )$
where dudt is a function of t and u which
determines diff(u,t).
Table 1: Methods for One First Order ODE
We will use these four different methods to solve the first order ordinary differential equation
du
= et + u
dt
subject to the condition that when t = 2,
(3.1)
u = 0.1.
4
If the differential equation has the structure Left(dudt,u,t) = Right(dudt,u,t) ( here u is the dependent variable and t is
the independent variable), we can always rewrite that differential equation as de = Left(dudt,u,t) - Right(dudt,u,t) = 0,
or de = 0.
We can use the syntax ode2(de,u,t), with the first argument an expression which includes derivatives, instead of the complete equation including the = 0 on the end, and ode2 will assume we mean de = 0 for the differential equation. (Of
course you can also use ode2 ( de=0, u, t)
We rewrite our example linear first order differential equation Eq. 3.1 in the way just described, using the noun form
diff, which uses a single quote. We then use ode2, and call the general solution gsoln.
(%i1) de : diff(u,t)- u - exp(-t);
du
- t
(%o1)
-- - u - %e
dt
(%i2) gsoln : ode2(de,u,t);
- 2 t
%e
t
(%o2)
u = (%c - -------) %e
2
The general solution returned by ode2 contains one constant of integration %c, and is an explicit solution for u as a function of t, although the above does not bind the symbol u.
We next find the particular solution which has t = 2, u = 0.1 using ic1, and call this particular solution psoln. We
then check the returned solution in two ways: 1. does it satisfy the conditions given to ic1?, and 2. does it produce a zero
value for our expression de?
(%i3) psoln : ic1(gsoln,t = 2, u = -0.1),ratprint:false;
- t - 4
2
2 t
4
%e
((%e - 5) %e
+ 5 %e )
(%o3)
u = - ----------------------------------10
(%i4) rhs(psoln),t=2,ratsimp;
1
(%o4)
- -10
(%i5) de,psoln,diff,ratsimp;
(%o5)
0
Both tests are passed by this particular solution. We can now make a quick plot of this solution using plot2d.
(%i6) us : rhs(psoln);
- t - 4
2
2 t
4
%e
((%e - 5) %e
+ 5 %e )
(%o6)
- ----------------------------------10
(%i7) plot2d(us,[t,0,7],
[style,[lines,5]],[ylabel," "],
[xlabel,"t0 = 2, u0 = -0.1, du/dt = exp(-t) + u"])$
5
which looks like
0
-0.5
-1
-1.5
-2
-2.5
-3
-3.5
-4
-4.5
-5
0
2
3
4
5
t0 = 2, u0 = -0.1, du/dt = exp(-t) + u
1
- -10
(%i8) plot2d(us,[t,0,7],
[style,[lines,5]],[ylabel," "],
[xlabel,"t0 = 2, u0 = -0.1, du/dt = exp(-t) + u"])$
and we get the same plot as before. The function desolve returns a solution in terms of the initial value u(0), which
here means u(t = 0), and we must go through an extra step to eliminate u(0) in a way that assures our chosen boundary condition t = 2, u - -0.1 is satisfied.
We have checked that the general solution satisfies the given differential equation in %i3, and have checked that our
particular solution satisfies the desired condition at t = 2 in %i7.
If your problem requires that the value of the solution us be specified at t = 0, the route to the particular solution is
much simpler than what we used above. You simply use subst ( u(0) = -1, rhs (gsoln) ) if, for example,
you wanted a particular solution to have the property that when t = 0, u = -1.
(%i9) us : subst( u(0) = -1,rhs(gsoln) ),ratsimp;
- t
2 t
%e
(%e
+ 1)
(%o9)
- ----------------2
(%i10) us,t=0,ratsimp;
(%o10)
- 1
du
d u = f (t0 , u0 ) d t = d t
(3.2)
d t t=t0 , u=u0
This equation determines the increase d u in the value of the dependent variable u induced by a small increase d t in the
independent variable t at the point (t0 , u0 ). We then define a local vector with t component d t and u component d u, and
draw a small arrow in that direction at a grid of chosen points to construct a direction field associated with the given first
order differential equation. The length of the small arrow can be increased some to reflect large values of the magnitude
of d u/d t.
For one first order ordinary differential equation, plotdf, has the syntax
plotdf( dudt,[t,u], [trajectory_at, t0, u0], options ... )
in which dudt is the function of (t,u) which determines the rate of change d u/d t.
-1
-2
-3
-4
-5
8
For our example first order ordinary differential equation, choosing the same initial conditions as above, and choosing
dt = 0.01,
(%i1)
(%i2)
(%i3)
(%o3)
(%i4)
fpprintprec:8$
points : rk (exp(-t) + u, u, -0.1, [ t, 2, 7, 0.01 ] )$
%, fll;
[[2, - 0.1], [7.0, - 4.7990034], 501]
plot2d( [ discrete, points ], [ t, 0, 7],
[style,[lines,5]],[ylabel," "],
[xlabel,"t0 = 2, u0 = -0.1, du/dt = exp(-t) + u"])$
(We have used our homemade function fll(x), loaded in at startup with the other functions defined in mbe1util.mac,
available with the Ch. 1 material. We have provided the definition of fll in the preface of this chapter. Instead of
%, fll ;, you could use [%[1],last(%),length(%)]; to get the same information.)
The plot looks like
0
-0.5
-1
-1.5
-2
-2.5
-3
-3.5
-4
-4.5
-5
2
4
5
t0 = 2, u0 = -0.1, du/dt = exp(-t) + u
3.3 Solution of One Second Order ODE or Two First Order ODEs
3.3.1 Summary Table
desolve
atvalue ( diff(u,t), t = 0, v(0) );
gsoln : desolve(de, u(t) );
where de includes the equal sign (=), diff(u(t),t,2),
and possibly diff(u(t),t) and
u(t).
plotdf
plotdf ( [dudt, dvdt], [u, v], [trajectory_at, u0, v0],
[u, umin, umax],[v, vmin, vmax], [tinitial, t0],
[direction,forward], [versus_t, 1],[tstep, timestepval],
[nsteps, nstepsvalue] )$
rk
points : rk ([dudt, dvdt ],[u, v],[u0, v0],[t, t0, tlast, dt] )$
where dudt and dvdt are functions of t,u, and v which
determine diff(u,t) and diff(v,t).
Table 2: Methods for One Second Order or Two First Order ODEs
We apply the above four methods to the simple second order ordinary differential equation:
d2 u
= 4u
d t2
subject to the conditions that when t = 2, u = 1 and d u/d t = 0.
3.3.2 Exact Solution with ode2, ic2, and eliminate
The main difference here is the use of ic2 rather than ic1.
(%i1) de : diff(u,t,2) - 4*u;
(%o1)
2
d u
--- - 4 u
2
dt
- 2 t
+ %k2 %e
(3.3)
10
0
0
0.5
1
1.5
2
2.5
3
U versus t, U(t) = 4 U(t), U(2) = 1, U(2) = 0
3.5
11
which produces the plot
du/dt vs u
t=1
t=2
t=3
10
-5
-10
0
Figure 5: t = 2, y = 1, y0 = 0 Solution
If your boundary conditions are, instead, for t=0, u = 1, and for t = 2, u = 4, then one can eliminate the
two constants by hand instead of using ic2 (see also next section).
(%i4) bc1 : subst(t=0,rhs(gsoln)) = 1$
(%i5) bc2 : subst(t = 2, rhs(gsoln)) = 4$
(%i6) solve(
eliminate([gsoln,bc1,bc2],[%k1,%k2]), u ),
ratsimp, ratprint:false;
- 2 t
4
4 t
8
4
%e
((4 %e - 1) %e
+ %e - 4 %e )
(%o6)
[u = -----------------------------------------]
8
%e - 1
(%i7) us : rhs(%[1]);
- 2 t
4
4 t
8
4
%e
((4 %e - 1) %e
+ %e - 4 %e )
(%o7)
----------------------------------------8
%e - 1
(%i8) us,t=0,ratsimp;
(%o8)
1
(%i9) us,t=2,ratsimp;
(%o9)
4
12
3.3.3 Exact Solution with desolve, atvalue, and eliminate
The function desolve uses Laplace transform methods which are set up to expect the use of initial values for dependent
variables and their derivatives. (However, we will show how you can impose more general boundary conditions.) If the
dependent variable is u(t), for example, the solution is returned in terms of a constant u(0), which refers to the value
of u(t = 0) (here we are assuming that the independent variable is t). To get a simple result from desolve which we
can work with (for the case of a second order ordinary differential equation), we can use the atvalue function with the
syntax (for example):
atvalue ( diff(u,t), t = 0, v(0) )
which will allow desolve to return the solution to a second order ODE in terms of the pair of constants ( u(0), v(0) ).
Of course, there is nothing sacred about using the symbol v(0) here. The function atvalue should be invoked before the
use of desolve.
If the desired boundary conditions for a particular solution refer to t = 0, then you can immediately find that particular
solution using the syntax (if ug is the general solution, say)
us : subst( [ u(0) = u0val, v(0) = v0val], ug ),
or else by using ratsubst twice.
In our present example, the desired boundary conditions refer to t = 2 , and impose conditions on the value of u and
its first derivative at that value of t. This requires a little more work, and we use eliminate to get rid of the constants
(u(0), v(0)) in a way that allows our desired conditions to be satisfied.
(%i1) eqn : diff(u(t),t,2) - 4*u(t) = 0;
2
d
(%o1)
--- (u(t)) - 4 u(t) = 0
2
dt
(%i2) atvalue ( diff(u(t),t), t=0, v(0) )$
(%i3) gsoln : desolve(eqn,u(t));
2 t
- 2 t
(v(0) + 2 u(0)) %e
(v(0) - 2 u(0)) %e
(%o3)
u(t) = --------------------- - ----------------------4
4
(%i4) eqn,gsoln,diff,ratsimp;
(%o4)
0 = 0
(%i5) ug : rhs(gsoln);
2 t
- 2 t
(v(0) + 2 u(0)) %e
(v(0) - 2 u(0)) %e
(%o5)
--------------------- - ----------------------4
4
(%i6) vg : diff(ug,t),ratsimp$
(%i7) ubc : subst(t = 2,ug) = 1$
(%i8) vbc : subst(t = 2,vg) = 0$
(%i9) solve (
eliminate([gsoln, ubc, vbc],[u(0), v(0)]), u(t) ),
ratsimp,ratprint:false;
- 2 t - 4
4 t
8
%e
(%e
+ %e )
(%o9)
[u(t) = -------------------------]
2
13
(%i10) us : rhs(%[1]);
- 2 t - 4
4 t
8
%e
(%e
+ %e )
(%o10)
------------------------2
(%i11) subst(t=2, us),ratsimp;
(%o11)
1
(%i12) vs : diff(us,t),ratsimp;
- 2 t - 4
4 t
8
(%o12)
%e
(%e
- %e )
(%i13) subst(t = 2,vs),ratsimp;
(%o13)
0
(%i14) plot2d(us,[t,0,4],[y,0,10],
[style,[lines,5]],[ylabel," "],
[xlabel," U versus t, U(t) = 4 U(t), U(2) = 1, U(2) = 0 "])$
plot2d: expression evaluates to non-numeric value somewhere in plotting range.
(%i15) for i thru 3 do
d[i]:[discrete,[float(subst(t=i,[us,vs]))]]$
(%i16) plot2d( [[parametric,us,vs,[t,1,3]],d[1],d[2],d[3] ],
[x,0,8],[y,-12,12],
[style, [lines,5,1],[points,4,2,1],
[points,4,3,1],[points,4,6,1]],
[ylabel," "],[xlabel," "],
[legend," du/dt vs u "," t = 1 ","t = 2","t = 3"] )$
which generates the same plots found with the ode2 method above.
If the desired boundary conditions are that u have given values at t = 0 and t = 3, then we can proceed from the
same general solution above as follows with up being a partially defined particular solution (assume u(0) = 1 and
u(3) = 2):
(%i17) up : subst(u(0) = 1, ug);
(%o17)
(%i18)
(%o18)
(%i19)
(%o19)
(%i20)
(%o20)
(%i21)
(%o21)
(%i22)
(%o22)
2 t
- 2 t
(v(0) + 2) %e
(v(0) - 2) %e
---------------- - -----------------4
4
ubc : subst ( t=3, up) = 2;
6
- 6
%e (v(0) + 2)
%e
(v(0) - 2)
-------------- - ---------------- = 2
4
4
solve(
eliminate ( [ u(t) = up, ubc ],[v(0)] ), u(t) ),
ratsimp, ratprint:false;
- 2 t
6
4 t
12
6
%e
((2 %e - 1) %e
+ %e
- 2 %e )
[u(t) = ------------------------------------------]
12
%e
- 1
us : rhs (%[1]);
- 2 t
6
4 t
12
6
%e
((2 %e - 1) %e
+ %e
- 2 %e )
-----------------------------------------12
%e
- 1
subst(t = 0, us),ratsimp;
1
subst (t = 3, us),ratsimp;
2
14
(%i23) plot2d(us,[t,0,4],[y,0,10],
[style,[lines,5]],[ylabel," "],
[xlabel," U versus t, U(t) = 4 U(t), U(0) = 1, U(3) = 2 "])$
plot2d: expression evaluates to non-numeric value somewhere in plotting range.
0
0
0.5
1
1.5
2
2.5
3
U versus t, U(t) = 4 U(t), U(0) = 1, U(3) = 2
3.5
15
which produces the plot
8
-2
0
0.5
1
1.5
2
2.5
3
U versus t, U(t) = 4 U(t), U(1) = -1, U(3) = 2
3.5
16
3.3.4 Numerical Solution and Plot with plotdf
Given a second order autonomous ODE, one needs to introduce a second dependent variable v(t), say, which is defined
as the first derivative of the original single dependent variable u(t). Then for our example, the starting ODE
d2 u
= 4u
d t2
is converted into two first order ODEs
(3.4)
dv
= 4u
dt
du
= v,
dt
and the plotdf syntax for two first order ODEs is
(3.5)
plotdf ( [dudt, dvdt], [u, v], [trajectory_at, u0, v0], [u, umin, umax],
[v, vmin, vmax], [tinitial, t0], [versus_t, 1],
[tstep, timestepval], [nsteps, nstepsvalue] )$
in which at t = t0, u = u0 and v = v0. If t0 = 0 you can omit the option [tinitial, t0]. The options
[u, umin, umax] and [v, vmin, vmax] allow you to control the horizontal and vertical extent of the phase
space plot (here v versus u) which will be produced. The option [versus_t,1] tells plotdf to create a separate plot
of both u and v versus the dependent variable. The last two options are only needed if you are not satisfied with the plots
and want to experiment with other than the default values of tstep and nsteps.
Another option you can add is [direction,forward], which will display the trajectory for t greater than or equal
to t0, rather than for a default interval around the value t0 which corresponds to [direction,both].
Here we invoke plotdf for our example.
(%i1) plotdf ( [v, 4*u], [u, v], [trajectory_at, 1, 0],
[u, 0, 8], [v, -10, 10], [versus_t, 1],
[tinitial, 2])$
u
v
-4
-8
0.8
1.2
1.6
2.4
2.8
3.2
17
and the phase space plot is
v
-4
-8
fpprintprec:8$
points : rk([v,4*u],[u,v],[1,0],[t,2,3.6,0.01])$
%, fll;
[[2, 1, 0], [3.6, 12.286646, 24.491768], 161]
uL : makelist([points[i][1],points[i][2]],i,1,length(points))$
%, fll;
[[2, 1], [3.6, 12.286646], 161]
18
(%i6) vL : makelist([points[i][1],points[i][3]],i,1,length(points))$
(%i7) %, fll;
(%o7)
[[2, 0], [3.6, 24.491768], 161]
(%i8) plot2d([ [discrete,uL],[discrete,vL]],[x,1,5],
[style,[lines,5]],[y,-1,24],[ylabel," "],
[xlabel,"t"],[legend,"u(t)","v(t)"])$
15
10
0
1
1.5
2.5
3
t
3.5
4.5
20
15
10
0
0
6
v vs. u
10
12
19
(%o1)
(%i2) gsoln : ode2(de,v,t);
- a t
(%o2)
v = %e
a t
g %e
(------- + %c)
a
0
20
For consistency, we must get the correct terminal speed for large t:
(%i6) assume(a>0)$
(%i7) limit( vs, t, inf );
g
a
(%o7)
As our dimensionless time u gets large, ws 1, which is the value of the terminal speed in dimensionless units.
Lets now plot three cases, two cases with initial speed less than terminal speed and one case with initial speed greater
than the terminal speed. (The use of dimensionless units for plots generates what are called universal curves, since they
are generally valid, no matter what the actual numbers are).
(%i11) plot2d([[discrete,[[0,1],[5,1]]],subst(w0=0,ws),subst(w0=0.6,ws),
subst(w0=1.5,ws)],[u,0,5],[y,0,2],
[style,[lines,2,7],[lines,4,1],[lines,4,2],[lines,4,3]],
[legend,"terminal speed", "w0 = 0", "w0 = 0.6", "w0 = 1.5"],
[ylabel, " "],
[xlabel, " dimensionless speed w vs dimensionless time u"])$
which produces:
2
terminal speed
w0 = 0
w0 = 0.6
w0 = 1.5
1.5
0.5
0
0
2
3
4
dimensionless speed w vs dimensionless time u
21
An object thrown down with an initial speed greater than the terminal speed (as in the top curve) slows down until its
speed is the terminal speed.
Thus far we have been only concerned with the relation between velocity and time. We can now focus on the implications
for distance versus time. A dimensionless length z is a2 y/g and the relation d y/d t = v becomes d z/d u = w, or
d z = w d u, which can be integrated over corresponding intervals: z over the interval [0, zf ], and u over the interval
[0, uf ].
(%i12) integrate(1,z,0,zf) = integrate(ws,u,0,uf);
- uf
uf
(%o12)
zf = - %e
(w0 - uf %e
- 1) + w0 - 1
(%i13) zs : expand(rhs(%)),uf = u;
- u
- u
(%o13)
- %e
w0 + w0 + %e
+ u - 1
(%i14) zs, u=0;
(%o14)
0
(Remember the object is launched at y = 0 which means at z = 0). Lets make a plot of distance travelled vs time
(dimensionless units) for the three cases considered above.
(%i15) plot2d([subst(w0=0,zs),subst(w0=0.6,zs),
subst(w0=1.5,zs)],[u,0,1],[style,[lines,4,1],[lines,4,2],
[lines,4,3]], [legend,"w0 = 0", "w0 = 0.6", "w0 = 1.5"],
[ylabel," "],
[xlabel,"dimensionless distance z vs dimensionless time u"],
[gnuplot_preamble,"set key top left;"])$
which produces:
1.4
w0 = 0
w0 = 0.6
w0 = 1.5
1.2
0.8
0.6
0.4
0.2
0
0
0.2
0.4
0.6
0.8
dimensionless distance z vs dimensionless time u
22
3.4.2 Ex. 2: One Nonlinear First Order ODE
Lets solve
x2 y
dy
= x y2 + x3 1
dx
(3.8)
This implicitly determines y as a function of the independent variable x By inspection, we see that x = 0 is a singular
point we should stay away from, so we assume from now on that x 6= 0.
To look at explicit solutions y(x) we use solve, which returns a list of two expressions depending on x. Since the implicit
solution is a quadratic in y, we will get two solutions from solve, which we call y1 and y2.
(%i4) [y1,y2] : map(rhs, solve(psoln,y)
2
2
2
sqrt(6 x log(x) + x + -)
x
(%o4)
[- --------------------------,
sqrt(3)
(%i5) [y1,y2], x = 1, ratsimp;
(%o5)
[- 1,
(%i6) de, diff, y= y2, ratsimp;
(%o6)
0
);
2
2
+ -)
x
--------------------------]
sqrt(3)
sqrt(6 x
log(x) + x
1]
We see from the values at x = 1 that y2 is the particular solution we are looking for, and we have checked that y2 satisfies
the original differential equation. From this example, we learn the lesson that ic1 sometimes needs some help in finding
the particular solution we are looking for.
Lets make a plot of the two solutions found.
(%i7) plot2d([y1,y2],[x,0.01,5],
[style,[lines,5]],[ylabel, " Y "],
[xlabel," X "] , [legend,"Y1", "Y2"],
[gnuplot_preamble,"set key bottom center;"])$
23
which produces:
10
8
6
4
2
0
-2
-4
-6
-8
Y1
Y2
-10
0.5
1.5
2.5
X
3.5
4.5
dx
dt
+ 5 x2 = 8
(3.9)
x = 0.
false
We see that direct use of ode2 does not succeed. We can use solve to get equations which are linear in the first derivative,
and then using ode2 on each of the resulting linear ODEs.
(%i3) solve(de,diff(x,t));
dx
2
dx
2
(%o3)
[-- = - sqrt(8 - 5 x ), -- = sqrt(8 - 5 x )]
dt
dt
(%i4) ode2 ( %[2], x, t );
5 x
asin(----------)
2 sqrt(10)
(%o4)
---------------- = t + %c
sqrt(5)
24
(%i5) solve(%,x);
2 sqrt(10) sin(sqrt(5) t + sqrt(5) %c)
[x = --------------------------------------]
5
(%i6) gsoln2 : %[1];
2 sqrt(10) sin(sqrt(5) t + sqrt(5) %c)
(%o6)
x = -------------------------------------5
(%i7) trigsimp ( ev (de,gsoln2,diff ) );
(%o7)
0
(%i8) psoln : ic1 (gsoln2, t=0, x=0);
solve: using arc-trig functions to get a solution.
Some solutions will be lost.
2 sqrt(10) sin(sqrt(5) t)
(%o8)
x = ------------------------5
(%i9) xs : rhs(psoln);
2 sqrt(10) sin(sqrt(5) t)
(%o9)
------------------------5
(%i10) xs,t=0;
(%o10)
0
(%o5)
We have selected only one of the linear ODEs to concentrate on here. We have shown that the solution satisfies the
original differential equation and the given boundary condition.
3.4.4 Ex. 4: Linear Oscillator with Damping
The equation of motion for a particle of mass m executing one dimensional motion which is subject to a linear restoring
force proportional to |x| and subject to a frictional force proportional to its speed is
m
d2 x
dx
+ kx = 0
+b
2
dt
dt
(3.10)
Dividing by the mass m, we note that if there were no damping, this motion would reduce to a linear oscillator with the
angular frequency
1/2
k
0 =
.
(3.11)
m
In the presence of damping, we can define
=
b
2m
(3.12)
d2 x
dx
+ 20 x = 0
+ 2
2
dt
dt
In the presence of damping, there are now two natural time scales
t1 =
1
,
0
t2 =
(3.13)
(3.14)
and we can introduce a dimensionless time = 0 t and the dimensionless positive constant a = /0 , to get
d2 x
dx
+x=0
+ 2a
d
d 2
(3.15)
25
The underdamped case corresponds to < 0 , or a < 1 and results in damped oscillations around the final x = 0.
The critically damped case corresponds to a = 1, and the overdamped case corresponds to a > 1. We specialize to
solutions which have the initial conditions = 0,
x = 1,
d x/d t = 0 d x/d = 0.
(%i1) de : diff(x,th,2) + 2*a*diff(x,th) + x ;
2
d x
dx
(%o1)
---- + 2 a --- + x
2
dth
dth
(%i2) for i thru 3 do
x[i] : rhs ( ic2 (ode2 (subst(a=i/2,de),x,th), th=0,x=1,diff(x,th)=0))$
(%i3) plot2d([x[1],x[2],x[3]],[th,0,10],
[style,[lines,4]],[ylabel," "],
[xlabel," Damped Linear Oscillator " ],
[gnuplot_preamble,"set zeroaxis lw 2"],
[legend,"a = 0.5","a = 1","a = 1.5"])$
which produces
1
a = 0.5
a=1
a = 1.5
x=0
0.8
0.6
0.4
0.2
-0.2
0
4
6
Damped Linear Oscillator: x vs theta
10
26
Now for a phase space plot with dx/dth versus x, drawn for the underdamped case:
(%i4)
(%i5)
(%i6)
(%o6)
(%i7)
v1 : diff(x[1],th)$
fpprintprec:8$
[x5,v5] : [x[1],v1],th=5,numer;
[- 0.0745906, 0.0879424]
plot2d ( [ [parametric, x[1], v1, [th,0,10],[nticks,80]],
[discrete,[[1,0]]], [discrete,[ [x5,v5] ] ] ],
[x, -0.4, 1.2],[y,-0.8,0.2], [style,[lines,3,7],
[points,3,2,1],[points,3,6,1] ],
[ylabel," "],[xlabel,"th = 0, x = 1, v = 0"],
[legend," v vs x "," th = 0 "," th = 5 "])$
which shows
0.2
v vs x
th = 0
th = 5
-0.2
-0.4
-0.6
-0.8
-0.4
-0.2
0.2
0.4
0.6
th = 0, x = 1, v = 0
0.8
1.2
27
(%i8) plotdf([v,-v-x],[x,v],[trajectory_at,1,0],
[direction,forward],[x,-0.4,1.2],[v,-0.6,0.2],
[nsteps,400],[tstep,0.01])$
This will bring up the phase space plot v vs. x, and you can thicken the red curve by clicking the Config button (which
brings up the Plot Setup panel), increasing the linewidth to 3, and then clicking ok. To actually see the thicker line, you
must then click on the Replot button. This plot is
v
-0.25
-0.5
0.5
x
v
0.5
-0.5
10
28
3.4.5 Ex. 5: Underdamped Linear Oscillator with Sinusoidal Driving Force
We extend our previous oscillator example by adding a sinusoidal driving force. The equation of motion is now
m
d2 x
dx
+b
+ k x = A cos( t)
2
dt
dt
0 =
As before, we define
=
k
m
(3.16)
1/2
.
(3.17)
b
.
2m
(3.18)
(3.19)
1
,
0
t2 =
1
,
t3 =
(3.20)
and we can introduce a dimensionless time = 0 t, the dimensionless positive damping constant a = /0 , the dimensionless oscillator displacement y = x/B, and the dimensionless driving angular frequency q = / 0 to get
d2 y
dy
2 + 2 a d + y = cos(q )
d
The underdamped case corresponds to < 0 , or a < 1, and we specialize to the case a = 1/2.
(%i1) de : diff(y,th,2) + diff(y,th) + y - cos(q*th);
2
d y
dy
(%o1)
---- + --- + y - cos(q th)
2
dth
dth
(%i2) gsoln : ode2(de,y,th);
2
q sin(q th) + (1 - q ) cos(q th)
(%o2) y = -------------------------------4
2
q - q + 1
- th/2
sqrt(3) th
sqrt(3) th
+ %e
(%k1 sin(----------) + %k2 cos(----------))
2
2
(%i3) psoln : ic2(gsoln,th=0,y=1,diff(y,th)=0);
2
q sin(q th) + (1 - q ) cos(q th)
(%o3) y = -------------------------------4
2
q - q + 1
4
2
sqrt(3) th
4
sqrt(3) th
(q - 2 q ) sin(----------)
q cos(----------)
- th/2
2
2
+ %e
(--------------------------------- + ------------------)
4
2
4
2
sqrt(3) q - sqrt(3) q + sqrt(3)
q - q + 1
(3.21)
29
We now specialize to a high (dimensionless) driving angular frequency case, q = 4, which means that we are assuming
that the actual driving angular frequency is four times as large as the natural angular frequency of this oscillator.
(%i4) ys : subst(q=4,rhs(psoln));
sqrt(3) th
sqrt(3) th
224 sin(----------)
256 cos(----------)
- th/2
2
2
(%o4) %e
(------------------- + -------------------)
241 sqrt(3)
241
4 sin(4 th) - 15 cos(4 th)
+ -------------------------241
(%i5) vs : diff(ys,th)$
We now plot both the dimensionless oscillator amplitude and the dimensionless oscillator velocity on the same plot.
(%i6) plot2d([ys,vs],[th,0,12],
[nticks,100],
[style,[lines,5]],
[legend," Y "," V "],
[xlabel," dimensionless Y and V vs. theta"])$
Y
V
0.8
0.6
0.4
0.2
0
-0.2
-0.4
-0.6
-0.8
-1
0
4
6
8
dimensionless Y and V vs. theta
10
12
30
We next make a phase space plot for the early capture part of the motion of this system. (Note that plotdf cannot
numerically integrate this differential equation because of the explicit appearance of the dependent variable.)
(%i7) plot2d([parametric,ys,vs,[th,0,8]],
[style,[lines,5]],[nticks,100],
[xlabel," V (vert) vs. Y (hor) "])$
0.4
0.2
-0.2
-0.4
-0.6
-0.8
-1
-0.4
-0.2
0.2
0.4
V (vert) vs. Y (hor)
0.6
0.8
d2
d
+ A cos( d t)
= z = m g L sin c
2
dt
dt
(3.22)
We introduce a dimensionless time = 0 t and a dimensionless driving angular frequency = d / 0 , where 20 = g/L,
to get the equation of motion
d2
d
+ b cos( )
(3.23)
= sin a
d2
d
To simplify the notation for our exploration of this differential equation, we make the replacements u, t, and
w ( parameters a, b, and w are dimensionless) to work with the differential equation:
d2 u
du
= sin u a
+ b cos(w t)
d t2
dt
(3.24)
where now both t and u are dimensionless, with the measure of u being radians, and the physical values of the pendulum
angle being limited to the range u , both extremes being the flip-over-point at the top of the motion.
We will use both plotdf and rk to explore this system, with
du
= v,
dt
dv
= sin u a v + b cos(w t)
dt
(3.25)
31
3.4.7 Free Oscillation Case
Using plotdf, the phase space plot for NO friction and NO driving torque is
(%i1) plotdf([v,-sin(u)],[u,v],[trajectory_at,float(2*%pi/3),0],
[direction,forward],[u,-2.5,2.5],[v,-2.5,2.5],
[tstep, 0.01],[nsteps,600])$
-1
-2
-2
-1
u
v
-1
-2
10
32
3.4.8 Damped Oscillation Case
We now include some damping with a = 1/2.
(%i2)
plotdf([v,-sin(u)-0.5*v],[u,v],[trajectory_at,float(2*%pi/3),0],
[direction,forward],[u,-1,2.5],[v,-1.5,1],
[tstep, 0.01],[nsteps,450])$
v
0.8
0.4
-0.4
-0.8
-1.2
-1
u
v
-1
10
12
Figure 24: With Friction, but No Driving Force: Angle U [blue] and V [red]
33
3.4.9 Including a Sinusoidal Driving Torque
We now use the Runge-Kutta function rk to integrate the differential equation set forward in time for ncycles, which
is the same as setting the final dimensionless tmax equal to ncycles*2*%pi/w, or ncycles*T, where we can call
T the dimensionless period defined by the dimensionless angular frequency w. The physical meaning of T is the ratio of
the period of the driving torque to the period of unforced and undamped small oscillations of the free simple pendulum.
For simplicity of exposition, we will call t the time and T the period. We again use our homemade function fll
described in the preface.
One cycle (period) of time is divided into nsteps subdivisions, so dt = T/nsteps.
For both the regular and chaotic parameter cases, we have used the same parameters as used in Mathematica in Theoretical Physics, by Gerd Baumann, Springer/Telos, 1996, pages 46 - 53.
3.4.10 Regular Motion Parameters Case
We find regular motion of this driven system with a = 0.2, b = 0.52, and w = 0.694, and with u0 = 0.8 rad,
and v0 = 0.8 rad/unit-time.
(%i1) fpprintprec:8$
(%i2) (nsteps : 31, ncycles : 30, a : 0.2, b : 0.52, w : 0.694)$
(%i3) [dudt : v, dvdt : -sin(u) - a*v + b*cos(w*t),
T : float(2*%pi/w ) ];
(%o3)
[v, - 0.2 v - sin(u) + 0.52 cos(0.694 t), 9.0535811]
(%i4) [dt : T/nsteps, tmax : ncycles*T ];
(%o4)
[0.292051, 271.60743]
(%i5) tuvL : rk ([dudt,dvdt],[u,v],[0.8,0.8],[t,0,tmax, dt])$
(%i6) %, fll;
(%o6)
[[0, 0.8, 0.8], [271.60743, - 55.167003, 1.1281164], 931]
(%i7) 930*dt;
(%o7)
271.60743
34
which produces
10
-10
-20
-30
-40
-50
u
v
-60
0
50
100
150
200
250
which produces (note that we include the early points which are more heavily influenced by the initial conditions):
-2
-4
-60
-50
-40
-30
v vs u
-20
-10
35
Reduced Phase Space Plot
Lets define a Maxima function reduce which brings u back to the interval (-pi, pi ) and then make a reduced phase space
plot. Since this is a strictly numerical task, we can simplify Maximas efforts by defining a floating point number pi once
and for all, and simply work with that definition. You can see the origin of our definition of reduce in the manuals
entry on Maximas modulus function mod.
(%i16)
(%o16)
(%i17)
(%i18)
(%o18)
(%i19)
(%o19)
(%i20)
pi : float(%pi);
3.1415927
reduce(yy) := pi - mod (pi - yy,2*pi)$
float( [-7*%pi/2,-3*%pi/2 ,3*%pi/2, 7*%pi/2] );
[- 10.995574, - 4.712389, 4.712389, 10.995574]
map(reduce, % );
[1.5707963, 1.5707963, - 1.5707963, - 1.5707963]
uvL_red : makelist ( [ reduce( tuvL[i][2]),
tuvL[i][3]],i,1,length(tuvL))$
(%i21) %, fll;
(%o21)
[[0.8, 0.8], [1.3816647, 1.1281164], 931]
To make a reduced phase space plot with our reduced regular motion points, we will only use the last two thirds of the
pairs (u,v). This will then show the part of the motion which has been captured by the driving torque and shows little
influence of the initial conditions.
We use the Maxima function rest (list, n) which returns list with its first n elements removed if n is positive. Thus we
use rest (list, num/3) to get the last two thirds.
(%i22) uvL_regular : rest (uvL_red, round(length (uvL_red)/3) )$
(%i23) %, fll;
(%o23)
[[0.787059, - 1.2368529], [1.3816647, 1.1281164], 621]
(%i24) plot2d ( [discrete,uvL_regular],[x,-3.2,3.2],[y,-3.2,3.2],
[style,[lines,2]],
[ylabel," "],[xlabel,"reduced phase space v vs u "] )$
which produces
3
-1
-2
-3
-3
-2
-1
0
1
reduced phase space v vs u
36
Poincare Plot
We next construct a Poincare plot of the regular (reduced) phase space points by using a stroboscopic view of this phase
space, displaying only phase space points which correspond to times separated by the driving period T. We select (u,v)
pairs which correspond to intervals of time n*T, where n = 10, 11, ..., 30 which will give us 21 phase space
points for our plot (this is roughly the same as taking the last two thirds of the points).
The time t = 30*T corresponds to t = 30*31*dt = 930*dt which is the time associated with element 931,
the last element) of uvL_red. The value of j used to select the last Poincare point is the solution of the equation
1 + 10*nsteps + j*nsteps = 1 + ncycles*nsteps, which for this case is equivalent to
311 + j*31 = 931.
(%i25) solve(311 + j*31 = 931);
(%o25)
[j = 20]
(%i26) pL : makelist (1+10*nsteps + j*nsteps, j, 0, 20);
(%o26) [311, 342, 373, 404, 435, 466, 497, 528, 559, 590, 621, 652, 683, 714,
745, 776, 807, 838, 869, 900, 931]
(%i27) length(pL);
(%o27)
21
(%i28) poincareL : makelist (uvL_red[i], i, pL)$
(%i29) %,fll;
(%o29)
[[0.787059, - 1.2368529], [1.3816647, 1.1281164], 21]
(%i30) plot2d ( [discrete,poincareL],[x,-0.5,2],[y,-1.5,1.5],
[style,[points,1,1,1 ]],
[ylabel," "],[xlabel," Poincare Section v vs u "] )$
0.5
-0.5
-1
-1.5
-0.5
0.5
1
Poincare Section v vs u
1.5
37
3.4.11 Chaotic Motion Parameters Case.
To exhibit an example of chaotic motion for this system, we use the same initial conditions for u and v, but use the
parameter set a = 1/2, b = 1.15, w = 2/3.
(%i1) fpprintprec:8$
(%i2) (nsteps : 31, ncycles : 240, a : 1/2, b : 1.15, w : 2/3)$
(%i3) [dudt : v, dvdt : -sin(u) - a*v + b*cos(w*t),
T : float(2*%pi/w ) ];
v
2 t
(%o3)
[v, - - - sin(u) + 1.15 cos(---), 9.424778]
2
3
(%i4) [dt : T/nsteps, tmax : ncycles*T ];
(%o4)
[0.304025, 2261.9467]
(%i5) tuvL : rk ([dudt,dvdt],[u,v],[0.8,0.8],[t,0,tmax, dt])$
(%i6) %, fll;
(%o6)
[[0, 0.8, 0.8], [2261.9467, 26.374502, 0.937008], 7441]
(%i7) dt*( last(%) - 1 );
(%o7)
2261.9467
(%i8) tuL : makelist ([tuvL[i][1],tuvL[i][2]],i,1,length(tuvL))$
(%i9) %, fll;
(%o9)
[[0, 0.8], [2261.9467, 26.374502], 7441]
(%i10) tvL : makelist ([tuvL[i][1],tuvL[i][3]],i,1,length(tuvL))$
(%i11) %, fll;
(%o11)
[[0, 0.8], [2261.9467, 0.937008], 7441]
(%i12) plot2d([ [discrete,tuL], [discrete,tvL]],[x,0,2000],
[y,-15,30],
[style,[lines,2]],[xlabel,"t"], [ylabel, " "],
[legend, "u","v" ] ,[gnuplot_preamble,"set key bottom;"])$
which produces a plot of u(t) and v(t) over 0 <= t <= 2000:
30
25
20
15
10
5
0
-5
-10
u
v
-15
0
500
1000
t
1500
Figure 29: Angle u(t), and v(t) for Chaotic Parameters Choice
2000
38
Phase Space Plot
We next construct a non-reduced phase space plot, but show only the first 2000 reduced phase space points.
(%i13)
(%i14)
(%o14)
(%i15)
(%i16)
(%o16)
(%i17)
which produces
3
-1
-2
-3
-10
-5
10
v vs u
15
20
25
30
Figure 30: non-reduced phase space plot using first 2000 points
If we use the discrete default style option lines instead of points,
(%i18) plot2d ( [discrete,uvL_first],[x,-12,30],[y,-3,3],
[ylabel," "],[xlabel," v vs u "])$
we get the non-reduced phase space plot drawn with lines between the points:
3
-1
-2
-3
-3
-2
-1
0
1
reduced phase space v vs u
Figure 31: non-reduced phase space plot using first 2000 points
39
Reduced Phase Space Plot
We now construct the reduced phase space points as in the regular motion case and then omit the first 400.
(%i19) pi : float(%pi);
(%o19)
3.1415927
(%i20) reduce(yy) := pi - mod (pi - yy,2*pi)$
(%i21) uvL_red : makelist ( [ reduce( first( uvL[i] )),
second( uvL[i] ) ],i,1,length(tuvL))$
(%i22) %, fll;
(%o22)
[[0.8, 0.8], [1.2417605, 0.937008], 7441]
(%i23) uvL_cut : rest(uvL_red, 400)$
(%i24) %, fll;
(%o24)
[[0.25464, 1.0166641], [1.2417605, 0.937008], 7041]
We have discarded the first 400 reduced phase space points in defining uvL_cut. If we now only plot the first 1000 of
the points retained in uvL_cut:
(%i25) uvL_first : rest (uvL_cut, -6041)$
(%i26) %, fll;
(%o26)
[[0.25464, 1.0166641], [2.2678603, 0.608686], 1000]
(%i27) plot2d ( [discrete,uvL_first],[x,-3.5,3.5],[y,-3,3],
[style,[points,1,1,1]],
[ylabel," "],[xlabel,"reduced phase space v vs u "])$
-1
-2
-3
-3
-2
-1
0
1
reduced phase space v vs u
40
produces the plot
3
-1
-2
-3
-3
-2
-1
0
1
reduced phase space v vs u
which produces
3
-1
-2
-3
-3
-2
-1
0
1
reduced phase space v vs u
41
and again, the same set of points drawn with the default lines option
(%i32) plot2d ( [discrete,uvL_first],[x,-3.5,3.5],[y,-3,3],
[ylabel," "],[xlabel,"reduced phase space v vs u "])$
-1
-2
-3
-3
-2
-1
0
1
reduced phase space v vs u
Figure 35: 3000 points reduced phase space plot
42
Poincare Plot
We now construct the Poincare section plot as before, using all the points available in uvL_red.
(%i33)
(%i34)
(%o34)
(%i35)
(%i36)
(%o36)
(%i37)
4
3
2
1
0
-1
-2
-3
-4
-3
-2
-1
0
Poincare Section v vs u
43
We see that contrib_ode, with the same syntax as ode, returns a list (here with one solution, but in general more than
one solution) rather than simply one answer.
Moreover, the package includes the Maxima function ode check which can be used to confirm the general solution.
Here is a comparison for our second order ODE example.
(%i7) de : diff(u,t,2) - 4*u;
(%o7)
2
d u
--- - 4 u
2
dt
- 2 t
+ %k2 %e
2 t
(%o9)
[u = %k1 %e
(%i10) ode_check(de, %[1] );
(%o10)
+ %k2 %e
- 2 t
]
Here is an example of an ODE which ode2 cannot solve, but contrib ode can solve.
(%i11) de : diff(u,t,2) + diff(u,t) + t*u;
2
d u
du
(%o11)
--- + -- + t u
2
dt
dt
(%i12) ode2(de,u,t);
(%o12)
false
44
This section will probably be augmented in the future with more examples of using contrib ode.
This document is part of a series of notes titled Maxima by Example and is made available
via the author's webpage
http://www.csulb.edu/woollett/
These notes (with some modications) will be published in book form eventually via Lulu.com in an arrangement which will continue to allow unlimited free download of the pdf les as well as the option of ordering
a low cost paperbound version of these notes.
Solving Equations
Maxima has several functions which can be used for solving sets of algebraic equations and for nding the
roots of an expression. These are described in the Maxima manual, Sec. 21, and listed under Contents under
Equations.
This chapter gives examples of the following Maxima functions:
solve solves a system of simultaneous linear or nonlinear polynomial equations for the specied variable(s) and returns a list of the solutions.
linsolve solves a system of simultaneous linear equations for the specied variables and returns a list of
the solutions.
nd root uses a combination of binary search and Newton-Raphson methods for univariate functions
and will nd a root when provided with an interval containing at least one root.
allroots nds all the real and complex roots of a real univariate polynomial.
realroots nds all of the real roots of a univariate polynomial within a specied tolerance.
linsolve by lu solves a system of linear algebraic equations by the matrix method known as LU decomposition, and provides a Maxima method to work with a set of linear equations in terms of the matrix of
coefcients.
newton, naive univariate Newton-Raphson, and mnewton, multivariate Newton-Raphson, can deal with
nonlinear function(s).
We also encourage the use of two dimensional plots to approximately locate solutions.
This chapter does not yet include Solving Recurrence Relations, and Solving One Hundred Equations.
4.1
4.1.1
Maxima's ability to solve equations is limited, but progress is being made in this area. The Maxima manual has an extensive entry for the important function solve, which you can view in Maxima with the input
? solve (no semicolon) followed by (Enter), or the equivalent command: describe(solve)$. The input example(solve)$ will show you the manual examples without the manual syntax material. We will
present some examples of the use of solve and not try to cover everything.
solve tries to nd exact solutions. If solve
simplied version of the original problem. Sometimes the simplied version can be useful:
(%i1) f(x);
(%o1)
f(x)
(%i2) solve( f(x)2-1 , x );
(%o2)
[f(x) = - 1, f(x) = 1]
Since Maxima's idea of what is simpler may not agree with your own, often the returned version is of no use.
The Maxima manual solve syntax discussion relevant to solving one equation is:
(expr, x)
(expr)
Function: solve
Function: solve
expr for the variable x and returns a list of solution equations in x. If expr
expr = 0 is assumed in its place. x may be a function (e.g. f(x)), or
other non-atomic expression except a sum or product. x may be omitted if expr contains only one variable.
expr may be a rational expression, and may contain trigonometric functions, exponentials, etc.
breakup if false will cause solve to express the solutions of cubic or quartic equations as single
expressions rather than as made up of several common subexpressions which is the default.
multiplicities will be set to a list of the multiplicities of the individual solutions returned by solve,
realroots, or allroots.
Try apropos (solve) for the switches which affect solve. describe may then by used on the
individual switch names if their purpose is not clear.
It is important to recognise that the rst argument to solve is either an equation such as f(x) = g(x) (or
h(x) = 0), or simply h(x); in the latter case, solve understands that you mean the equation h(x) = 0,
and the problem is to nd the roots of h(x), ie., values of x such that the equation h(x) = 0 is satised.
Here we follow the manual suggestion about using apropos and describe:
(%i1) apropos(solve);
(%o1) [solve, solvedecomposes, solveexplicit, solvefactors, solvenullwarn,
solveradcan, solvetrigwarn, solve_inconsistent_error]
(%i2) describe(solveradcan)$
-- Option variable: solveradcan
Default value: `false'
When `solveradcan' is `true', `solve' calls `radcan' which makes
`solve' slower but will allow certain problems containing
exponentials and logarithms to be solved.
(%i3) describe(solvetrigwarn)$
-- Option variable: solvetrigwarn
Default value: `true'
When `solvetrigwarn' is `true', `solve' may print a message saying
that it is using inverse trigonometric functions to solve the
equation, and thereby losing solutions.
4.1.2
Let's start with a simple example where the expected answers are obvious and check the behavior of solve. In
particular we want to check solve's behavior with both an expression and a function (dened via
:=). We also
want to check how the system list multiplicities is created and maintained. We include the use of realroots
and allroots in this comparison, even though we will not have to use these latter two functions for a while.
(%i1) multiplicities;
(%o1)
(%i2) ex1 : x2 - 2*x + 1;
(%o2)
not_set_yet
2
x - 2 x + 1
(%i3) factor(ex1);
(%o3)
(%i4) g(x) := x2 - 2*x + 1$
(%i5) g(y);
(%o5)
(%i6) solve(ex1);
(%o6)
(%i7) multiplicities;
(%o7)
(%i8) solve(g(y));
(%o8)
(%i9) multiplicities;
(%o9)
(%i10) realroots(ex1);
(%o10)
(%i11) multiplicities;
(%o11)
(%i12) allroots(ex1);
(%o12)
(%i13) multiplicities;
(%o13)
2
(x - 1)
2
y - 2 y + 1
[x = 1]
[2]
[y = 1]
[2]
[x = 1]
[2]
[x = 1.0, x = 1.0]
[2]
We see that we can use either an expression or a function with solve, and you can check that this also applies
to realroots and allroots. It is not clear from our use of allroots above how allroots affects multiplicities,
although, as we will see later, the manual does not assert any connection, and we would not expect there to be a
connection because allroots returns multiple roots explicitly in
%o12.
(%i1) multiplicities;
(%o1)
not_set_yet
(%i2) allroots(x2 - 2*x + 1);
(%o2)
[x = 1.0, x = 1.0]
(%i3) multiplicities;
(%o3)
not_set_yet
As we expected, allroots does not affect multiplicities; only solve and realroots set its value.
4.1.3
To get our feet wet, lets turn on the machinery with a general quadratic equation or expression. There are
some differences if you employ an expression rather than a function dened with
:=.
advantages and some disadvantages. Let's rst use the function argument, rather than an expression argument.
We will later show how the calculation is different if an expression is used. We will step through the process of
verifying the solutions and end up with a do loop which will check all the solutions. We will use a function
f(x) which depends parametrically on (a,b,c) as the rst argument to solve, and rst see what happens if
we don't identify the unknown: how smart is Maxima??
(%i2) f(y);
2
(%o2)
a y + b y + c
(%i3) sol : solve( f(x) );
More unknowns than equations - `solve'
Unknowns given :
[a, x, b, c]
Equations given:
2
[a x + b x + c]
-- an error. To debug this try debugmode(true);
We see that Maxima cannot read our mind! We must tell Maxima which of the four symbols is to be considered
the unknown. From Maxima's point of view (actually the point of view of the person who wrote the code),
one equation cannot determine four unknowns, so we must supply the information about which of the four
variables is to be considered the unknown.
4.1.4
(%i5) s1 : sol[1];
(%o5)
Now we can use the
2
sqrt(b - 4 a c) + b
x = - -------------------2 a
The simple one-argument form of solve can be used if all but one of the symbols in the expression is already
bound.
2
[x = -]
3
[1, 2, 3]
solve(a*x2 + b*x + c);
[x = - sqrt(2) %i - 1, x = sqrt(2) %i - 1]
[a,b,c] : [4,5,6];
[4, 5, 6]
solve(a*x2 + b*x + c);
sqrt(71) %i + 5
sqrt(71) %i - 5
(%o15)
[x = - ---------------, x = ---------------]
8
8
(%i16) [a,b,c] : [4,5,6];
(%o16)
[4, 5, 6]
4.1.6
We have seen above examples of using disp, which can be used to print out the values of symbols or text, and
display, which can be used to print out the name of the symbol and its value in the form of an equation:
x = value.
Here is the do loop check of the roots of the quadratic found above using print instead of disp.
(%i17) [a,b,c];
(%o17)
(%i18) f(x);
(%o18)
(%i19) kill(a,b,c);
(%o19)
(%i20) [a,b,c];
(%o20)
(%i21) f(x);
(%o21)
[4, 5, 6]
2
4 x + 5 x + 6
done
[a, b, c]
2
a x + b x + c
(%i22) sol;
(%o22)
(%i23)
expr =
expr =
2
2
sqrt(b - 4 a c) + b
sqrt(b - 4 a c) - b
[x = - --------------------, x = --------------------]
2 a
2 a
for i:1 thru 2 do print("expr = ", expand( subst(sol[i],f(x) ) ) )$
0
0
)$
0
0
The only tricky thing about this kind of code is getting the parentheses to balance. Note that that expand(...) is
inside print, so the syntax used is do print(... ), ie., a one job do . The outside parentheses allow the syntax
( job1, job2 ). Note also that the default start of the do loop index is 1, so we can use an abbreviated
syntax that does not have the i:1 beginning.
4.1.7
f(x) dened via := as the rst argument to solve is that it is fairly easy
to check the roots by using the map function. We want to use the syntax map( f, solnlist}, where
solnlist is a list of the roots (not a list of replacement rules). To get the solution list we can again use map
with the syntax map(rhs, sol}.
%i27
shows a compact method which avoids having to name the solnlist and which also
avoids having to look at the intermediate output. When you see someone's example written in a compact form
like this, you should realize that the someone probably tried out the progression of steps one step at a time
(just like we did) to see the correct route, and once the path to the result has been found, reduced the result to
8
the minimum number of steps and names. Often, one does not know in advance which progression of steps
will succeed, and one must experiment before nding the true path. You should take apart the compact
code, by reading from the inside out (ie., from right to left), and also try getting the result one step at a time to
get comfortable with the method and notation being used.
4.1.8
Psuedo-PostFix Code: %%
An alternative psuedo-postx (ppf) notation can be used which allows one to read the line from left to right,
following the logical succession of procedures being used. Although this ppf notation costs more in keystrokes
(an extra pair of outside parentheses, extra commas, and entry of double percent signs
usually easier for beginners to follow, and it is easier to mentally balance parentheses as well. As an example,
the previous double map check of the roots can be carried out as:
( job1, job2(%%), job3(%%),... ). The system variable %% has the manual description (in part):
System variable:
%%
ous statement.
4.1.9
Let's rework the general quadratic equation solution, including the checks of the solutions, using an expression
Thus far, the methods have been similar. If we now bind the values of
of our solutions using
[1, 2, 3]
2
a x + b x + c
ex remains bound to the same general expression. The symbol ex retains its original
binding. We can make use of the values given to (a,b,c) with the expression ex by using two single quotes,
which forces an extra evaluation of the expression ex by the Maxima engine, and which then makes use of the
extra information about (a,b,c).
(%i10) ''ex;
2
x + 2 x + 3
(%o10)
(%i11) ex;
2
a x + b x + c
(%o11)
Forcing the extra evaluation in
using map, as we did before. To use map we need a function, rather than an expression to map on a solution
list. Let's try to dene such a function
(%i12) f(x);
(%o12)
(%i13) f(x) := ex;
(%o13)
(%i14) f(y);
(%o14)
(%i15) f(x) := ''ex;
(%o15)
(%i16) f(y);
(%o16)
(%i17) kill(a,b,c);
(%o17)
(%i18) f(y);
2
f(x) := a x + b x + c
2
y + 2 y + 3
done
2
(%o18)
a y + b y + c
(%i19) solnlist : map(rhs,sol);
2
2
sqrt(b - 4 a c) + b sqrt(b - 4 a c) - b
(%o19)
[- --------------------, --------------------]
2 a
2 a
10
(%i20) map(f,solnlist);
2
2
2
(sqrt(b - 4 a c) + b)
b (sqrt(b - 4 a c) + b)
(%o20) [----------------------- - ------------------------ + c,
4 a
2 a
2
2
2
(sqrt(b - 4 a c) - b)
b (sqrt(b - 4 a c) - b)
----------------------- + ------------------------ + c]
4 a
2 a
(%i21) expand(%);
(%o21)
[0, 0]
Output %14 showed that the syntax f(x) := ex did not succeed in dening the function we need. The input
f(x) := ''ex suceeded in getting a true function of x, but now the function f(x) automatically makes
use of the current binding of (a,b,c), so we had to kill those values to get a function with arbitrary values
of (a,b,c). Having the function in hand, we again used the map function twice to check the solutions. Now
that we have discovered the true path, we can restart Maxima and present the method as:
2
f(x) := a x + b x + c
2
(%o6)
a y + b y + c
(%i7) expand ( map(f, map(rhs, sol) ) );
(%o7)
[0, 0]
We can also use the unnamed, anonymous function lambda to avoid introducing needless names, like :
In this section we solve a physics problem which involves a simple quadratic equation. It is so simple that doing it on paper is faster than doing it with Maxima. In fact, once you understand the plan of the calculation,
you can come up with the nal formula for the escape speed in your head. However, we will present practical
details of setup and evaluation which can be used with more messy problems, when you might want to use
Maxima.
Let's use conservation of mechanical energy (kinetic plus potential) to rst calculate the initial radial speed
a rocket must have near the surface of the earth to achieve a nal required radial speed far from the earth (far
11
m, the mass of the earth be M, the radius of the earth be R, a general radial distance
r >= R, a general radial rocket speed be v, the maximum speed of the rocket
near the surface of the earth be v0, and the nal radial speed of the rocket (as r becomes innite) be vf.
At a general distance r from the center of the earth the rocket has kinetic energy ke = m*v2/2, and
gravitational energy pe = -G*M*m/r, where G is the gravitational constant:
(G = 6.673 10(-11) newton*meter2/kg2).
Let the mass of the rocket be
m v
m G M
---- - ----2
r
e0 corresponds to the energy the rocket has achieved at the moment of maximum radial
speed: this will occur at a radius r slightly larger than the radius of the earth R, but negligible error to the
required lift-off speed v0 will be made by ignoring this difference in radius. (You can justify this as a
The initial energy
good approximation by getting the answer when including this small difference, and comparing the percent
difference in the answers.)
(%i2) e0 : energy,v=v0,r=R;
(%o2)
2
m v0
m G M
----- - ----2
R
r becomes larger, and the magnitude of the gravitational energy becomes smaller. The
nal energy efinal will be the energy when the gravitational energy is so small that we can ignore it; in
As the rocket rises,
practice this will occur when the magnitude of the gravitational energy is much smaller than the magnitude of
the inital gravitational energy. The radial outward speed of the rocket then remains a constant value
vf.
2
m vf
----2
If we neglect the loss of mechanical energy due to friction in leaving the earth's atmosphere, and also neglect
other tiny effects like the gravitational interaction between the moon and the rocket, the sun and the rocket,
etc, then we can approximately say that the total mechanical energy (as we have dened it) of the rocket is a
constant, once chemical energy used to increase the rocket's speed is no longer a factor (which occurs at the
moment of maximum radial speed).
We can then get one equation by approximately equating the mechanical energy of the rocket just after achieving maximum speed to the mechanical energy of the rocket when
12
2 G M
2
v0 = sqrt(----- + vf )
R
(%o7)
v0
2 G M
2
sqrt(----- + vf )
R
This provides the required lift-off speed near the surface of the earth to achieve a given nal radial speed
vf.
We now want to nd the escape speed, the minimum value of the lift-off speed which will allow the rocket
to escape the gravitational pull of the earth. Any rocket which has a radial speed when
r is effectively innite
will succeed in escaping, no matter how small that radial speed is. The limiting initial speed is then gotten by
taking the limit of
v0 as vf goes to zero.
G M
sqrt(2) sqrt(---)
R
(%o8)
Uing the mass of the earth, M = 5.974 10(24) kg, and the radius of the earth,
R = 6.378 10(6) meters, we get an escape speed 11,181 m/s = 11.18 km/s.
float:true),
gets the
sqrt(2) in
oating point.
Looking at all those digits is unnecessary; set fpprintprec to something reasonable (this only affects the
numbers presented on the screen, not the accuracy of the calculation):
(%i13) fpprintprec:8$
(%i14) ev( vescape, clist, float );
(%o14)
11180.621
(%i15) clist;
(%o15)
[G = 6.673E-11, M = 5.974E+24, R = 6378000.0]
13
4.1.11
Here is an example of using solve to solve a cubic equation, or, in the alternative language, nd the roots
of a cubic expression. After checking the roots via the map function, we assign the values of the roots to the
(x1,x2,x3). The cubic expression we choose is especially simple, with no arbitrary parameters, so
symbols
(%i1) ex : x3 + x2 + x$
(%i2) sol : solve(ex);
sqrt(3) %i + 1
sqrt(3) %i - 1
(%o2)
[x = - --------------, x = --------------, x = 0]
2
2
(%i3) define( f(x), ex )$
(%i4) expand ( map(f, map(rhs, sol) ) );
(%o4)
[0, 0, 0]
(%i5) [x1,x2,x3] : map(rhs,sol);
sqrt(3) %i + 1 sqrt(3) %i - 1
(%o5)
[- --------------, --------------, 0]
2
2
(%i6) x1;
sqrt(3) %i + 1
(%o6)
- -------------2
4.1.12
(%i1) [fpprintprec:8,display2d:false]$
(%i2) ex : sin(x)2 -2*sin(x) -3$
(%i3) sol : solve(ex);
`solve' is using arc-trig functions to get a solution.
Some solutions will be lost.
(%o3) [x = asin(3),x = -%pi/2]
(%i4) define( f(x), ex )$
(%i5) expand ( map(f, map(rhs, sol) ) );
(%o5) [0,0]
(%i6) numroots : float( map(rhs, sol) );
(%o6) [1.5707963-1.7627472*%i,-1.5707963]
The rst solution returned is the angle (in radians) whose sin is 3.
-1 <=
sin(x) <= 1
For real
x, sin(x)
. Thus we have found one real root. But we have been warned that some solutions
(%i7) rr : realroots(ex);
(%o7) [sin(x) = -1,sin(x) = 3]
However, by realroots, realroots means that the numbers
14
We can of course take the output of realroots and let solve go to work.
We can make a simple plot of our expression to see the periodic behavior and the approximate location of
the real roots.
0.0
sin(x)2-2*sin(x)-3
-2
-4
-6
-4
-2
0
x
(%i18) plot2d([0.0,ex3],[x,-6,6],[y,-5,5] )$
4.1.13
Here is an example submitted to the Maxima mailing list and a method of solution provided by Maxima
developer Stavros Macrakis. The problem is to nd the roots of the following expression
ex:
(%i1) [fpprintprec:8,display2d:false,ratprint:false]$
(%i2) ex : log(0.25*(2*x+5)) - 0.5*log(5*x - 5)$
We rst try solve, with the option variable solveradcan set equal to true. Remember that the syntax
%o2.
(expr)
fullratsimp repeatedly applies ratsimp followed by non-rational simplication to an expression until
Function: fullratsimp
ratsimp
(general) simplication may not be sufcient to return a simplied result. Sometimes, more than one such
The effect of fullratsimp in our case results in the decimals being replaced by exact fractions.
(%i4) ex : fullratsimp(ex);
(%o4) (2*log((2*x+5)/4)-log(5*x-5))/2
The logarithms can be combined using the Maxima function logcontract.
(expr)
Function: logcontract
2 4
a log(x y )
(%o2)
Here is the application to our problem:
(%i5) ex : logcontract(ex);
(%o5) -log((80*x-80)/(4*x2+20*x+25))/2
Having combined the logarithms, we try out solve on this expression:
We have already tried out the Maxima functions realroots and allroots. The most important restriction for
both of these numerical methods is that the expression or equation be a polynomial, as the manual explains:
(eqn, bound)
(expr)
Function: realroots(eqn)
Function: realroots
Function: realroots
realroots assigns the multiplicities of the roots it nds to the global variable multiplicities.
16
realroots
constructs a Sturm sequence to bracket each root, and then applies bisection to rene the
approximations. All coefcients are converted to rational equivalents before searching for roots, and computations are carried out by exact rational arithmetic. Even if some coefcients are oating-point numbers,
Here are the startup values of the option variables just mentioned:
(%i1) fpprintprec:8$
(%i2) [multiplicities,rootsepsilon,programmode];
(%o2)
[not_set_yet, 1.0E-7, true]
The function allroots also accepts only polynomials, and nds numerical approximations to both real and
complex roots:
(expr)
Function: allroots(eqn)
Function: allroots
Computes numerical approximations of the real and complex roots of the polynomial
equation
The ag
causes
allroots
expr or polynomial
if the polynomial is real, or over the complex numbers, if the polynomial is complex (default setting of
polyfactor is false).
allroots may give inaccurate results in case of multiple roots.
If the polynomial is real, allroots (%i*p)) may yield more accurate approximations than allroots(p),
as allroots invokes a different algorithm in that case.
allroots rejects non-polynomials. It requires that the numerator after rat'ing should be a polynomial, and
it requires that the denominator be at most a complex number. As a result of this, allroots will always
return an equivalent (but factored) expression, if polyfactor is true.
Here we test the default value of polyfactor:
(%i3) polyfactor;
(%o3)
4.2.1
false
Let's nd the real and complex roots of a fth order polynomial which solve cannot solve, doesn't factor,
and use both realroots and allroots.
17
Next we nd numerical approximations to the three real roots and the two (complex-conjugate) roots of the
given polynomial, using allroots
( ex ) and substitute the obtained roots back into the expression to see how
( %i* ex ).
(expr) (which was used to get ar1), than by the syntax allroots(%i*expr), used to get
ar2. We also see that the syntax allroots(%i*expr) introduced a tiny complex piece to the dominant real
part. The two extra complex roots found by the rst syntax (ar1) are the complex conjugate of each other. The
two extra complex roots found by the alternative syntax (ar2) are also the complex conjugate of each other to
4.2.2
1 2
x x 18 intersect? We want
2
approximate numerical values. We can plot the two functions together and use the cursor to read off the values
h(x) = x3 8 x2 + 19 x 12
and
k(x) =
for which the curves cross, and we can also nd the roots numerically. We rst dene the curves as
expressions depending on
x, then dene the difference of the expressions (rx) to work with using allroots rst
to see if all the (three) roots are real, and then using realroots just for fun, and then checking the solutions.
If we are just going to compare the results with a plot, we don't need any great accuracy, so we will use the
default realroots precision.
(%i1)
(%i2)
(%i3)
(%i4)
(%o4)
fpprintprec : 8$
hx : x3 - 8*x2 + 19*x - 12$
kx : x2/2 -x -1/8$
rx : hx - kx;
2
3
17 x
95
x - ----- + 20 x - -2
8
18
(%i5) factor(rx);
(%o5)
3
2
8 x - 68 x + 160 x - 95
------------------------8
sx1 holds the exact roots of the cubic polynomial which solve found. We see that the form returned
has explicit factors of %i. We already know that the roots of this polynomial are purely real. How can we get
The list
the exact roots into a form where it is obvious that the roots are real? The Maxima expert Alexey Beshenov
(via the Maxima mailing list) suggested using rectform, followed by trigsimp. Using rectform gets rid of the
factors of
The quantity
values:
trigsimp( expand
(%i17)
(%o17)
(%i18)
(%o18)
(%i19)
(%o19)
the alge-
Let's next plot the three functions, using the expressions hx, kx, and rx (the difference).
10
hx
kx
rx=hx - kx
-5
-10
-15
0
x
Figure 2: Intersection Points are Zeroes of rx
Here is code you can use to make something close to the above plot.
(%i20) plot2d([hx,kx,rx],[x,0,5],
[style, [lines,2,1], [lines,2,2], [lines,2,0] ],
[legend, "hx", "kx", "rx=hx - rx"],
[gnuplot_preamble, " set xzeroaxis lw 2 "])$
When you place the cursor over the places on the
x axis where the expression rx is zero, you can read off the
x coordinate (the rst) is the desired root.
20
4.2.3
nd root
A transcendental equation is an equation containing a transcendental function. Examples of such equations are
x = ex and x = sin(x). The logarithm and the exponential function are examples of transcendental functions.
We will include the trigonometric functions, i.e., sine, cosine, tangent, cotangent, secant, and cosecant in this
category of functions. (A function which is not transcendental is said to be algebraic. Examples of algebraic
functions are rational functions and the square root function.)
To nd the roots of transcendental expressions, for example, we can rst make a plot of the expression, and
then use nd root knowing roughly where nd root should start looking. The Maxima manual provides a lot
of details, beginning with:
(expr, x, a, b)
(f, a, b)
expr or the function f over the closed interval [a, b]. The expression
expr may be an equation, in which case find_root seeks a root of lhs(expr) - rhs(expr).
Given that Maxima can evaluate expr or f over [a, b] and that expr or f is continuous, find_root
is guaranteed to nd the root, or one of the roots if there is more than one.
0.6
0.4
0.2
0
-0.2
-0.4
-0.6
-0.8
-1
0
0.2
0.4
0.6
plot of x - cos(x)
0.8
We can use either an expression or function as the entry to the rst slot of nd root. I nd that the most
common mistake I make with nd root is to leave out the underline between nd and root, in which case,
I simply get back the unevaluated ndroot(ex, x, 0, 1), since Maxima has no knowledge of ndroot (unless
I create a homemade function with that name).
21
We can make a plot, nd the root in a variety of ways using nd root, and verify the accuracy of the root
as follows:
(%i1) fpprintprec:8$
(%i2) plot2d( x - cos(x), [ x, 0, 1 ],
[style, [lines, 4, 1] ],
[xlabel," plot of x - cos(x) "],
[gnuplot_preamble, "set nokey; set xzeroaxis lw 2 "] )$
(%i3) find_root( x - cos(x),x, 0, 1);
(%o3)
0.739085
(%i4) ex : x - cos(x)$
(%i5) [find_root( ex, x, 0, 1),find_root( ex, 0, 1)];
(%o5)
[0.739085, 0.739085]
(%i6) define( f(x), ex )$
(%i7) [find_root(f(x), x, 0, 1), find_root(f(x), 0, 1),
find_root(f, 0, 1), find_root(f, x, 0, 1)];
(%o7)
[0.739085, 0.739085, 0.739085, 0.739085]
(%i8) ev(ex, x = first(%) );
(%o8)
0.0
As a second example, we will nd the roots of the function
2
f (x).
0.5
-0.5
-1
-1.5
-2
-2.5
0
3
plot of f(x)
[x = 2.53, x = 2.97].
22
(%i1) fpprintprec:8$
(%i2) f(x):= cos(x/%pi)*exp(-(x/4)2) - sin(x(3/2)) - 5/4$
(%i3) plot2d(
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
f(x),[x,0,5],
[style, [lines,4,1] ],
[xlabel," plot of f(x) "],[ylabel," "],
[gnuplot_preamble, "set nokey; set xzeroaxis lw 2 "] )$
[find_root(f,2.5,2.6), find_root(f, x, 2.5, 2.6),
find_root(f(x),x,2.5,2.6), find_root(f(y),y,2.5,2.6)];
[2.5410501, 2.5410501, 2.5410501, 2.5410501]
[x1 : find_root(f,2.5,2.6),x2 : find_root(f, 2.9, 3.0 )];
[2.5410501, 2.9746034]
float( map(f, [x1,x2] ) );
[3.33066907E-16, 2.77555756E-16]
We see that the numerical accuracy of nd root using default behavior is the normal accuracy of Maxima
arithmetic.
4.2.4
nd root has been purposely designed to allow uses like the following:
(%i1) fpprintprec:8$
(%i2) find_root(diff(cos(2*x)*sin(3*x)/(1+x2),x), x, 0, 0.5);
(%o2)
0.321455
nd root evaluates the derivative and parks the resulting expression in the code function fr(x),say, to be used
to probe where the function changes sign, as the code executes a bisection search for a root in the range called
for. The code rst checks that the sign of the function fr(x) has opposite signs at the end points of the given
range. Next the code makes small steps in one direction, checking at each step if a sign change has occurred.
As soon as a sign change has occurred, the code backs up one step, cuts the size of the step in half, say, and
starts stepping again, looking for that sign change again. This is a brute force method which will nd that
root if there is one in the given interval. Of course the user can always evaluate the derivative and submit the
resulting expression to nd root to nd the same answer, as in:
23
If we assign the delayed derivative to an expression ex1, we can then use an argument
ev(ex1,diff) to
(%i6) ex1 :
'diff(cos(2*x)*sin(3*x)/(1+x2),x);
d cos(2 x) sin(3 x)
(%o6)
-- (-----------------)
dx
2
x + 1
(%i7) find_root(ev(ex1,diff),x,0,0.5);
(%o7)
0.321455
If we assign the delayed derivative to a function g(x), and assign
that most of the time you can get correct results without using the single quote syntax
'(f(x)).
All of the
following examples give the correct answer for this simple function.
However, one can arrive at specialized homemade functions which require the strict syntax (a quoted function entry in the rst slot) to behave correctly. Suppose we need to nd the numerical roots of a function dened
by an integral. The following is a toy model which uses such a function in a case where we know the answer
2
ahead of time. Instead
of directly looking for the roots of the function f (x) = (x 5), we look for the roots
Rx
of the function 2 y d y .
5
(%i1) fpprintprec : 8$
(%i2) ex : integrate(2*'y,'y,sqrt(5),x);
2
x
5
(%o2)
2 (-- - -)
2
2
(%i3) ex : expand(ex);
2
(%o3)
x - 5
(%i4) define( f(x), ex );
2
(%o4)
f(x) := x - 5
(%i5) solve( ex );
(%o5)
[x = - sqrt(5), x = sqrt(5)]
(%i6) rr : float( map(rhs,%) );
(%o6)
[- 2.236068, 2.236068]
(%i7) map(f,rr);
(%o7)
[8.8817842E-16, 8.8817842E-16]
(%i8) find_root(f,0,4);
(%o8)
2.236068
Let's concentrate on nding the root
Dene a function
g(x)
in terms of integrate:
g(x)
However, if
we replace integrate with quad qags, we nd problems. First let's show the numerical integration routine
quad qags at work by itself:
(%i13) quad_qags(2*'y,'y,sqrt(5),2);
(%o13)
[- 1.0, 1.11076513E-14, 21, 0]
(%i14) g(2.0);
(%o14)
- 1.0
The quad qags function returns a list of four items, the rst being the numerical value of the integral, the second
being an estimate of the error of the answer calculated, the third being the number of function evaluations
required, and the last an error code. The returned error code
will write a function which ignores the error code returned, although in real life we would always want to
report an error code value which was not
0.
25
Here we dene
h(x) in
find_root( h(x),x,1,4) produced an error due to the way nd root evaluates
the rst slot. Somehow nd root assigned -5.0 to the internal function fr(x) used to look for the root, and in
We see that the syntax
the rst steps of that root location, checking for a difference in sign of fr(x) and the range end points, found the
value
-5.0 at both ends. In effect, the code was working on the problem find_root( -5.0, x, 1, 4).
newton
The Maxima function newton can also be used for numerical solutions of a single equation. The Maxima
manual describes the syntax as:
(%i1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
fpprintprec:8$
load (newton1);
C:/PROGRA1/MAXIMA3.0/share/maxima/5.14.0/share/numeric/newton1.mac
newton (cos (u), u, 1, 1/100);
1.5706753
ev (cos (u), u = %);
1.21049633E-4
assume (a > 0);
[a > 0]
26
2
6.09849048E-4 a
(%o7)
c:\Program Files\Maxima-5.14.0\share\maxima\5.14.0\share\numeric.
Here is the
newton(exp,var,x0,eps):=
block([xn,s,numer],
numer:true,
s:diff(exp,var),
xn:x0,
loop,
if abs(subst(xn,var,exp))<eps then return(xn),
xn:xn-subst(xn,var,exp)/subst(xn,var,s),
go(loop)
)$
We see that the code implements the Newton-Raphson algorithm. Given a function f (x) and an initial guess
xg which can be assigned to, say, xi , a closer approximation to the value of x for which f (x) = 0 is generated
by
i+1
f (xi )
=x 0 i .
f (x )
i
Steven Koonin's (edited) comments (Computational Physics: Fortran Version, Steven E. Koonin and Dawn
Meredith, WestView Press, 1998, Ch. 1, Sec.3) are cautionary:
When the function
f (x) is badly behaved near its root (e.g., there is an inection point near the root) or when
there are several roots, the automatic Newton-Raphson method can fail to converge at all or converge to
the wrong answer if the initial guess for the root is poor.
27
4.3
is a list of the unknowns to be determined. If the total number of variables in the equations is equal to the
number of equations, the second argument-list may be omitted.
4.3.1
The Maxima functions solve, linsolve, and linsolve by lu can be used for linear equations.
Linear equations containing symbolic coefcients can be solved by solve and linsolve. For example the
pair of equations
ax + by = c, dx + ey = f
. Here we solve for the values of
solutions.
(%i5) linsolve(eqns,[x,y]);
(%o5)
4.3.2
3
1
[x = -, y = -]
2
2
The present version (5.14) of the Maxima manual does not have an index entry for the function linsolve by lu.
These notes include only the simplest of many interesting examples described in two mailing list responses by
the creator of the linear algebra package, Barton Willis (Dept. of Mathematics, Univ. Nebraska at Kearney),
dated Oct. 27, 2007 and Nov. 21, 2007.
If we re-cast the two equation problem we have just been solving in the form of a matrix equation
A . xcol = bcol, we need to construct the square matrix A so that matrix multiplication by the column
xcol results in a column vector whose rows contain the left hand sides of the equations. The column
vector bcol rows hold the right hand sides of the equations. Our notation below ( as xycol and xylist )
vector
is only natural for a two equation problem (ie., a 2 x 2 matrix): you can invent your own notation to suit your
problem.
If the argument of the function matrix is a simple list, the result is a row vector (a special case of a matrix
object). We can then take the transpose of the row matrix to obtain a column matrix, such as
A direct denition of a two element column matrix is
matrix([x],[y]),
xcol below.
transpose(matrix([x,y])). To reduce the amount of space taken up by the default matrix output, we
can set display2d:false.
(%i6) m : matrix( [3,-1],[1,1] );
(%o6)
(%i7) display2d:false$
(%i8) m;
(%o8) matrix([3,-1],[1,1])
(%i9) xcol : matrix([x],[y]);
(%o9) matrix([x],[y])
(%i10) m . xcol;
(%o10) matrix([3*x-y],[y+x])
[ 3
[
[ 1
- 1 ]
]
1 ]
(%i11)
(%o11)
(%i12)
(%o12)
(%i13)
(%o13)
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
b : [4,2];
[4,2]
linsolve_by_lu(m,b);
[matrix([3/2],[1/2]),false]
xycol : first(%);
matrix([3/2],[1/2])
m . xycol - b;
matrix([0],[0])
xylist : makelist( xycol[i,1],i,1,length(xycol) );
[3/2,1/2]
xyrules : map("=",[x,y],xylist);
[x = 3/2,y = 1/2]
29
The matrix argument needs to be a square matrix. The output of linsolve by lu is a list: the rst element is the
xycol.
%i14. The output %o14 is a column vector each of whose elements is zero;
such a column vector is ordinarily replaced by the number 0.
solution column vector which for this two dimensional problem we have called
We check the solution in input
One should always check solutions when using computer algebra software, since the are occasional bugs in
the algorithms used. The second list element returned by linsolve by lu is false, which should always be the
value returned when the calculation uses non-oating point numbers as we have here. If oating point numbers
are used, the second element should be either false or a lower bound to the matrix condition number. (We
show an example later.) We have shown how to convert the returned
and how to then construct a list of replacement rules (as would be returned by linsolve) which could then be
used for other purposes. The use of makelist is the recommended way to use parts of matrix objects in lists.
However, here is a simple method which avoids makelist:
(%i18)
(%i19)
(%o19)
(%i20)
(%o20)
4.3.3
bcol : matrix([4],[2])$
linsolve_by_lu(m,bcol);
[matrix([3/2],[1/2]),false]
m . first(%) - bcol;
matrix([0],[0])
ax + by = c,
seeking the values of
dx + ey = f,
(x,y) which simultaneously satisfy these two equations and checking the solutions.
(%i1)
(%i2)
(%i3)
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
display2d:false$
m : matrix( [a,b], [d,e] )$
bcol : matrix( [c], [f] )$
ls : linsolve_by_lu(m,bcol);
[matrix([(c-b*(f-c*d/a)/(e-b*d/a))/a],[(f-c*d/a)/(e-b*d/a)]),false]
xycol : ratsimp( first(ls) );
matrix([-(b*f-c*e)/(a*e-b*d)],[(a*f-c*d)/(a*e-b*d)])
( m . xycol - bcol, ratsimp(%%) );
matrix([0],[0])
(display2d:true,xycol);
[ b f - c e ]
[ - --------- ]
[ a e - b d ]
(%o7)
[
]
[ a f - c d ]
[ --------- ]
[ a e - b d ]
(%i8) determinant(m);
(%o8)
a e - b d
30
4.3.4
Next we show how one can solve for multiple solutions (with one call to linsolve by lu) corresponding to a
number of different right hand sides. We will turn back on the default matrix display, and re-dene the rst
(right hand side) column vector as
(%i21) display2d:true$
(%i22) b1col : matrix( [4], [2] );
(%o22)
(%i23)
(%o23)
(%i24)
(%o24)
(%i25)
(%o25)
(%i26)
(%o26)
(%i27)
(%o27)
(%i28)
(%o28)
[ 4 ]
[
]
[ 2 ]
x1col : first( linsolve_by_lu(m,b1col) );
[ 3 ]
[ - ]
[ 2 ]
[
]
[ 1 ]
[ - ]
[ 2 ]
b2col : matrix( [3], [1] );
[ 3 ]
[
]
[ 1 ]
x2col : first( linsolve_by_lu(m, b2col) );
[ 1 ]
[
]
[ 0 ]
bmat : matrix( [4,3], [2,1] );
[ 4 3 ]
[
]
[ 2 1 ]
linsolve_by_lu( m, bmat );
[ 3
]
[ - 1 ]
[ 2
]
[[
], false]
[ 1
]
[ - 0 ]
[ 2
]
xsolns : first(%);
[ 3
]
[ - 1 ]
[ 2
]
[
]
[ 1
]
[ - 0 ]
[ 2
]
31
(%o30)
[ 0
[
[ 0
[
[
[
[
[
[
[
0 ]
]
0 ]
3 ]
- ]
2 ]
]
1 ]
- ]
2 ]
[ 1 ]
[
]
[ 0 ]
%i26 we dene the 2 x 2 matrix bmat whose rst column is b1col and whose second column
b2col. Using bmat as the second argument to linsolve by lu results in a return list whose rst element
(what we call xsolns) is a 2 x 2 matrix whose rst column is x1col (the solution vector corresponding
to b1col) and whose second column is x2col (the solution vector corresonding to b2col). In input %i29
In input
is
we check both solutions simultaneously. The result is a matrix with every element equal to zero, which would
ordinarily be replaced by the number
4.3.5
We next consider a simple three linear equation example. Although solve does not require the list
[x,y,z]
in this problem, if you leave it out, the solution list returned will be in an order determined by the peculiarities
of the code, rather than by you. By including the variable list as
(%i6) linsolve(eqns,[x,y,z]);
(%o6) [x = 7/10,y = 9/5,z = 3/2]
Notice that linsolve returns a list, while solve returns a list of lists.
32
Next we use linsolve by lu on this three equation problem. Using the laws of matrix multiplication, we
reverse engineer the
3 3 matrix m and the three element column vector bcol which provide an equivalent
(%i1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%i5)
(%o5)
(%i6)
(%o6)
%i4 binds an equation to the symbol e which can be removed with kill.
33
do ( job1, job2 )
Let's try out linsolve by lu on this three linear (in the unknowns
involves the unbound parameter
a.
(x,y,z))
(%i8) display2d:false$
(%i9) m : matrix([1,-1,1],[2*a,-1,0],[0,1,-2] )$
(%i10) xcol : matrix( [x],[y],[z] )$
(%i11) m . xcol;
(%o11) matrix([z-y+x],[2*a*x-y],[y-2*z])
(%i12) bcol : matrix( [0],[2*a2], [2] )$
(%i13) soln : linsolve_by_lu(m,bcol)$
(%i14) xyzcol : ( first(soln), ratsimp(%%) );
(%o14) matrix([a+1],[2*a],[a-1])
(%i15) ratsimp( m . xyzcol - bcol);
(%o15) matrix([0],[0],[0])
%i15 we check the solution, and the result is a three element column vector, all of whose elements are
zero. Such a column matrix is ordinarily replaced by the number 0.
In input
4.3.6
If we start with two linear equations with decimal coefcients, solve (and the other methods) converts the decimals to ratios of integers, and tries to nd an exact solution. You can avoid seeing all the rational replacements
done by setting the option variable ratprint to false. Despite the assertion, in the manual section on rat, that
keepfloat if true prevents oating point numbers from being converted to rational numbers.
setting keepoat to true here does not stop solve from converting decimal numbers to ratios of integers.
(%i1)
(%o1)
(%i2)
(%i3)
(%i4)
(%i5)
`rat'
`rat'
`rat'
`rat'
`rat'
`rat'
(%o5)
(%i6)
`rat'
[keepfloat,ratprint];
[false, true]
display2d:false$
fpprintprec:8$
eqns : [0.2*x + 0.3*y = 3.3,0.1*x - 0.8*y = 6.6]$
solns : solve(eqns, [x,y]);
replaced -3.3 by -33/10 = -3.3
replaced 0.2 by 1/5 = 0.2
replaced 0.3 by 3/10 = 0.3
replaced -6.6 by -33/5 = -6.6
replaced 0.1 by 1/10 = 0.1
replaced -0.8 by -4/5 = -0.8
[[x = 462/19,y = -99/19]]
linsolve(eqns,[x,y]);
replaced -3.3 by -33/10 = -3.3
34
column vectors).
4.3.7
Here is an example of using solve to nd a pair of exact solutions of a pair of equations, one equation being
linear, the other quadratic. The pair of solutions represent the two intersections of the unit circle with the line
y = x/3.
(%i1) fpprintprec:8$
(%i2) eqns : [x2 + y2 = 1, x + 3*y = 0]$
(%i3) solns : solve(eqns,[x,y]);
3
1
(%o3) [[x = - --------, y = ---------------],
sqrt(10)
sqrt(2) sqrt(5)
3
1
[x = --------, y = - ---------------]]
sqrt(10)
sqrt(2) sqrt(5)
35
x y, y x.
A set of two nonlinear polynomial equations with four solutions generated by solve is one of the examples
in the Maxima manual. One of the solutions is exact, one is a real inexact solution, and the other two solutions
are inexact complex solutions.
(%i1) fpprintprec:8$
(%i2) eqns : [4*x2 - y2 = 12, x*y - x = 2]$
(%i3) solns : solve( eqns, [x,y] );
(%o3) [[x = 2, y = 2], [x = 0.520259 %i - 0.133124,
y = 0.0767838 - 3.6080032 %i], [x = - 0.520259 %i - 0.133124,
y = 3.6080032 %i + 0.0767838], [x = - 1.7337518, y = - 0.153568]]
(%i4) for i thru 2 do for j thru length(solns) do (
expand( ev(eqns[i],solns[j]) ),
abs( lhs(%%) - rhs(%%) ), disp(%%) )$
0
2.36036653E-15
2.36036653E-15
1.13954405E-6
0
0.0
0.0
9.38499825E-8
To get real numbers from the complex solutions, we used the abs function, which calculates the absolute value
of a complex number. Note the syntax used to check the solutions:
36
4.3.8
Solving systems of nonlinear equations is much more difcult than solving one nonlinear equation. A wider
variety of behavior is possible: determining the existence and number of solutions or even a good starting
guess is more complicated. There is no method which can guarantee convergence to the desired solution. The
computing labor increases rapidly with the number of dimensions of the problem.
4.3.9
Given two circles, we seek the intersections points. We rst write down the dening equations of the two
circles, and look visually for points
plot for
x and y ranges to make the circles circular, but we can use the cursor
to read off approximate intersections points: (x,y) = (0.26,0.98), (0.96,0.30). However, the
We are not taking enough care with the
x y,
y between the two equations and use solve to nd accurate values for
the x's. Since we know that both solutions have positive values for y, we enforce this condition on equation 1.
respect this symmetry. We next eliminate
(%i5) solve(eq1,y);
2
2
(%o5)
[y = - sqrt(1 - x ), y = sqrt(1 - x )]
(%i6) ysoln : second(%);
2
(%o6)
y = sqrt(1 - x )
(%i7) eliminate(eqns,[y]);
2
(%o7)
[32 x - 40 x + 9]
(%i8) xex : solve(first(%));
sqrt(7) - 5
sqrt(7) + 5
(%o8)
[x = - -----------, x = -----------]
8
8
(%i9) (fpprintprec:8, xex : float(xex) );
(%o9)
[x = 0.294281, x = 0.955719]
(%i10) [x1soln : first(xex), x2soln : second(xex) ]$
(%i11) [ev(%o7,x1soln), ev(%o7,x2soln)];
(%o11)
[[- 4.4408921E-16], [0.0]]
(%i12) y1soln : ev(ysoln,x1soln);
(%o12)
y = 0.955719
(%i13) y2soln : ev(ysoln,x2soln);
(%o13)
y = 0.294281
(%i14) [soln1:[x1soln,y1soln],soln2:[x2soln,y2soln] ]$
(%i15) [ev(eqns,soln1), ev(eqns,soln2) ];
(%o15)
[[1.0 = 1, 4.0 = 4], [1.0 = 1, 4.0 = 4]]
(%i16) [soln1,soln2];
(%o16) [[x = 0.294281, y = 0.955719], [x = 0.955719, y = 0.294281]]
37
%o16) which respect the symmetry of the equations. The solutions have been numerically
checked in input %i15.
We have solutions (
-1
-2
-3
-2
-1
4.3.10
The gure above was created using the draw package with the following code in a separate work le implicitplot1.mac. The code the the le is
/* file implicitplot1.mac */
/* need load(implicit_plot); to use this code */
disp(" doplot() ")$
doplot() := block([ x,y, eq1, eq2, y1:-2, y2:4,r, x1 ,x2 ],
r : 1.56,
x1 : r*y1,
x2 : r*y2,
eq1 : x2 + y2 = 1,
eq2 : (x-2)2 + (y-2)2 = 4,
draw2d(
grid
= true,
line_type = solid,
line_width = 3,
color = blue,
implicit(eq1, x, x1,x2, y, y1,y2),
color = red,
implicit(eq2, x, x1,x2, y, y1,y2),
color = black,
point_type = filled_circle,
point_size = 2,
38
(%i1) load(draw);
(%o1) C:/PROGRA1/MAXIMA3.0/share/maxima/5.14.0/share/draw/draw.lisp
(%i2) load(implicitplot1);
doplot()
(%o2)
(%i3) doplot();
(%o3)
c:/work2/implicitplot1.mac
[gr2d(implicit, implicit, points)]
Note that no actual plot was drawn on the screen, since an eps le was created mycircle2.eps in my
work folder
c:\work2 for use in my latex le. To use this code to get a gure on your screen, you would
terminal = 'eps , file_name = "c:/work2/mycircle2" and,
very important!, also remove the comma at the end of two circles.
4.3.11
Another Example
We next work through Example 6.5.1 (page 149), in Numerical Methods for Unconstrained Optimization and
Nonlinear Equations by J. E. Dennis, Jr. and Robert B. Schnabel (Prentice-Hall, 1983).
(%i1) eq1 : x2 + y2 = 2;
2
2
(%o1)
y + x = 2
(%i2) eq2 : exp(x - 1) + y3 = 2;
3
x - 1
(%o2)
y + %e
= 2
We will concentrate on the solution
(%i3) eliminate([eq1,eq2],[y]);
2 x
x + 1
2 6
(%o3)
[%e
- 4 %e
+ %e x
(%i4) ex : first(%);
2 x
x + 1
2 6
(%o4)
%e
- 4 %e
+ %e x
(%i5) plot2d([0.0,ex],[x,-5,5] )$
(%i6) plot2d([0.0,ex],[x,0,2] )$
(%i7) x1 : find_root(ex,x,0.5,1.5);
(%o7)
(%i8) yeqn : ev(eq1,x = x1);
2
(%o8)
y +
(%i9) solve(yeqn);
`rat' replaced -1.0 by -1/1 = -1.0
(%o9)
[y = -
2 4
2 2
2
- 6 %e x + 12 %e x - 4 %e ]
2 4
2 2
2
- 6 %e x + 12 %e x - 4 %e
1.0
1.0 = 2
1, y = 1]
39
(%i10)
(%o10)
(%i11)
(%o11)
(%i12)
(%o12)
(%i13)
(%o13)
ysol : second(%);
soln1 : [x = x1, ysol];
ev(eq1,soln1);
y = 1
[x = 1.0, y = 1]
2.0 = 2
ev(eq2,soln1);
2.0 = 2
1.5
0.5
-0.5
-1
-1.5
-3
-2
-1
0
X
(FuncList,VarList,GuessList)
Function: mnewton
Multiple nonlinear functions solution using the Newton method. FuncList is the list of functions to solve,
VarList is the list of variable names, and GuessList is the list of initial approximations.
The solution is returned in the same format that solve() returns. If the solution isn't found,
This function is controlled by global variables
[] is returned.
(%i1) load(mnewton);
(%o1) C:/PROGRA1/MAXIMA3.0/share/maxima/5.14.0/share/contrib/mnewton.mac
(%i2) mnewton([2*aa-5],[a],[1]);
(%o2)
[[a = 1.70927556786144]]
(%i3) mnewton([2*3u-v/u-5, u+2v-4], [u, v], [2, 2]);
(%o3)
[[u = 1.066618389595407, v = 1.552564766841786]]
(%i4) mnewton([x1+3*log(x1)-x22, 2*x12-x1*x2-5*x1+1],
[x1, x2], [5, 5]);
(%o4)
[[x1 = 3.756834008012769, x2 = 2.779849592817898]]
In the above examples, mnewton is presented with a list of expressions. Here we use mnewton on the
Dennis and Schnabel problem we solved earlier using eliminate and nd root. We rewrite the equations as
expressions here.
(%i1) fpprintprec:8$
(%i2) load(mnewton);
(%o2) C:/PROGRA1/MAXIMA3.0/share/maxima/5.14.0/share/contrib/mnewton.mac
(%i3) exs : [x2 + y2 -2, exp(x-1)+y3-2]$
(%i4) mn(x0,y0) := mnewton(exs,[x,y],[x0,y0] )$
(%i5) mn(1.1,0.9);
(%o5)
[[x = 1.0, y = 1.0]]
(%i6) mn(1.2,0.8);
(%o6)
[[x = 1.0, y = 1.0]]
(%i7) mn(1.3,0.7);
(%o7)
[[x = 1.0, y = 1.0]]
(%i8) mn(1.4,0.6);
(%o8)
[[x = 1.0, y = 1.0]]
(%i9) mn(1.5,0.5);
(%o9)
[[x = - 0.713747, y = 1.2208868]]
(%i10) mn(1.5,0.6);
(%o10)
[[x = 1.0, y = 1.0]]
(%i11) mn(1.7,0.6);
(%o11)
[[x = 1.0, y = 1.0]]
(%i12) mn(1.9,0.6);
(%o12)
[[x = - 0.713747, y = 1.2208868]]
(%i13) mn(1.9,0.7);
(%o13)
[[x = 1.0, y = 1.0]]
(%i14) mn(2,0.7);
(%o14)
[[x = 1.0, y = 1.0]]
(%i15) mn(0.8,1.1);
(%o15)
[[x = 1.0, y = 1.0]]
(%i16) mn(0.5,1.2);
(%o16)
[[x = 1.0, y = 1.0]]
(%i17) mn(0.1,1.2);
(%o17)
[[x = - 0.713747, y = 1.2208868]]
We have to be close enough to nd the (1,1) root with mnewton. Note that Maxima's function mnewton
can't nd the desired root starting with
success.
41
4.3.12
Let's explore the Newton Raphson method using an easy example which solve has no trouble with. As a byproduct, we show that mnewton can deal with a list of equations, rather than a list of expressions. After getting
an error message from Maxima's mnewton, we work this same problem by hand, using matrix methods. A
good reference is Chapter 5, Nonlinear Equations, of the text Scientic Computing: An Introductory Survey
(2nd ed.), by Michael T. Heath. ( see webpage:
http://www.cse.uiuc.edu/heath/scicomp/pubdata/index.html)
(%i18)
(%i19)
(%i20)
(%o20)
(%i21)
(%o21)
(%i22)
(%o22)
(%i23)
(%o23)
(%i24)
Maxima
eqns : [x+y=3,x2+y2=9]$
mn(x0,y0) := mnewton(eqns,[x,y],[x0,y0] )$
solve(eqns,[x,y]);
[[x = 3, y = 0], [x = 0, y
mn(1,2);
[[x = 6.37714165E-17, y =
mn(-1,4);
[[x = 6.37714165E-17, y =
mn(-2,5);
[[x = 1.13978659E-16, y =
mn(0,0);
encountered a Lisp error:
= 3]]
3.0]]
3.0]]
3.0]]
implement a naive (ie., a strategy-less) iteration algorithm as presented in Heath's text. We present the algorithm rst in terms of a
(x,y).
22
matrix and a two element column vector which are functions of the scalars
We then convert the algorithm to a form which works with two element column vectors
and
and we seek
v and b.
f (b) = 0,
f is a column vector which denes the problem. If b is an approximate solution of this equation, then
bbetter = b + s, where s is the solution of the matrix equation j(b) . s = -f(b), and the 2 2 matrix
j(b) is the jacobian matrix: j[1,1] : diff( f[1,1],x ), j[1,2] : diff( f[1,1],y ),
and j[2,1] : diff( f[2,1],x), j[2,2] : diff( f[2,1],y ).
where
(%i1) (fpprintprec:8,ratprint:false)$
(%i2) g : matrix( [x + y -3],[x2 + y2 -9] );
[ y + x - 3 ]
(%o2)
[
]
[ 2
2
]
[ y + x - 9 ]
42
43
(%i14) b : b + s;
(%o14)
(%i15) b : b + first(
(%o15)
(%i16) b : b + first(
(%o16)
(%i17) b : b + first(
(%o17)
(%i18) b : b + float(
(%o18)
(%i19) f(b);
[ - 1 ]
[
]
[ 4 ]
linsolve_by_lu(j(b),-f(b) ) );
[ 1 ]
[ - - ]
[ 5 ]
[
]
[ 16 ]
[ -- ]
[ 5
]
linsolve_by_lu(j(b),-f(b) ) );
[
1 ]
[ - -- ]
[
85 ]
[
]
[ 256 ]
[ --- ]
[ 85
]
linsolve_by_lu(j(b),-f(b) ) );
[
1 ]
[ - ----- ]
[ 21845 ]
[
]
[ 65536 ]
[ ----- ]
[ 21845 ]
first( linsolve_by_lu(j(b),-f(b) )
[ - 6.98491931E-10 ]
[
]
[
3.0
]
(%o19)
) );
[
0.0
]
[
]
[ 4.19095159E-9 ]
(x0,y0) = (1,2), this iteration process has converged to the approximate solu%o18, which we check as an approximate solution in input %i19. Now let's start with the
dangerous guess: (x0,y0) = (0,0).
Starting with the guess
tion given by
[0] );
[ 0 ]
[
]
[ 0 ]
[ - 3 ]
[
]
[ - 9 ]
[ 1
[
[ 0
1 ]
]
0 ]
44
(%i23) ls : linsolve_by_lu(j(b),-f(b) );
Division by 0
-- an error. To debug this try debugmode(true);
(%i24) determinant(j(b));
(%o24)
0
Thus, a check of the non-vanishing of the determinant of the jacobian matrix would have kept us out of trouble.
4.3.13
Writing code for an arbitrary number of dimensions is a suggested homework problem. Here we just assume
the problem is two dimensional and assume the variables are called
of the determinant of the jacobian, we ask if the absolute value is less than some very small number. Here
is the code, written with notepad2 in a le mymnewton.mac, placed in my work directory
c:\work2\.
You can download this le from the author's webpage, and experiment with it. You can reduce the size of
the output on the screen by adding the line
display2d:false,
gram in your work session. If you make changes to this code, add some extra debug printouts at rst like
display(newval1,newval2),
or
print(" v1 = ",v1),
track. Once the program has been debugged, you can comment out the debug version in your work le, copy
the whole code to a new section, remove the debug printouts, and use as your working version.
/* working version */
/* file: mymnewton.mac
e. woollett, april, 08 */
disp("working version mymnewton,
assumes two dimensional problem only,
syntax:
mymnewton( exprlist, guesslist, numiter )$
exprlist should have the form: [expr1, expr2],
to find (x,y) such that simultaneously expr1=0,expr2=0,
expr1, expr2 should be explicit functions of x and y,
guesslist should be in the form: [xguess,yguess],
numiter = number of iterations ")$
mymnewton( exprlist, guesslist, numiter) :=
block([numer,ratprint,fpprintprec, small : 1.0e-30 ,
g,x,y,gv,h,hv,b,v,ls,d ] , local(f,j),
numer:true, ratprint:false, fpprintprec:8,
/* g = col vec: row 1=expr 1, row 2=expr 2 depends on (x,y) */
g : matrix( [ exprlist[1] ],[ exprlist[2] ] ),
display(g),
gv : ev(g, x=v[1,1], y=v[2,1] ),
/* v is generic col vector */
45
define( f(v), gv ),
/* h is jacobian matrix associated with col vec g(x,y) */
h : matrix( [diff( g[1,1], x), diff( g[1,1], y)],
[diff( g[2,1], x), diff(g[2,1], y) ] ),
hv : ev(h, x=v[1,1], y=v[2,1] ),
define( j(v), hv ),
/* b is col vec containing (x,y) values */
b : matrix([ guesslist[1] ],[ guesslist[2] ]),
/*
start iterations */
first(ls)
) /* end do */
)$
/* end block */
46
(%i1) load("mymnewton.mac");
working version mymnewton,
assumes two dimensional problem only,
syntax:
mymnewton( exprlist, guesslist, numiter )$
exprlist should have the form: [expr1, expr2],
to find (x,y) such that simultaneously expr1=0,expr2=0,
expr1, expr2 should be explicit functions of x and y,
guesslist should be in the form: [xguess,yguess],
numiter = number of iterations
(%o1)
c:/work2/mymnewton.mac
(%i2) mymnewton([x+y-3, x2+y2-9],[1,2], 5)$
[ y + x - 3 ]
g = [
]
[ 2
2
]
[ y + x - 9 ]
i = 0
b =
starting values
[ 1 ]
[
]
[ 2 ]
f(b) =
[ - 1.0 ]
[
]
[ 4.0 ]
condition number = 22.5
i = 1
b =
[ - 0.2 ]
[
]
[ 3.2 ]
condition number = 19.5
i = 2
b =
[ 0 ]
[
]
[ - 4 ]
f(b) =
[ 0.0 ]
[
]
[ 8.0 ]
f(b) =
[ 0.0 ]
[
]
[ 1.28 ]
[ - 0.0117647 ]
[
]
[ 3.0117647 ]
condition number = 10.92
i = 3
b =
f(b) =
[ - 4.57770657E-5 ]
[
]
[
3.0000458
]
condition number = 7.212872
i = 4
b =
[ - 6.98491837E-10 ]
[
]
[
3.0
]
condition number = 7.000824
i = 5
b =
[
0.0
]
[
]
[ 0.0708651 ]
[ 4.4408921E-16 ]
f(b) = [
]
[ 2.74666585E-4 ]
[
0.0
]
f(b) = [
]
[ 4.19095159E-9 ]
47
i = 0
b =
[ 0 ]
[
]
[ 0 ]
starting values
abs(det(jacobian)) is
f(b) =
0.0
]
]
]
]
[ - 3 ]
[
]
[ - 9 ]
program halt
It is left as a homework problem to incorporate a criterion for nding an accurate enough solution without
providing the program a number of iterations, and allowing the program to hide the details of the iteration
process, providing the user with an answer and an estimate of the likely error.
48
5.1
This chapter provides an introduction to a new graphics interface developed by the author of the Maxima by
Example tutorial notes. The qdraw package ( qdraw.mac: available for download on the Maxima by Example
webpage ) is an interface to the draw package function draw2d; to obtain a plot you must load draw as well
load(qdraw) if you have the le in your work folder and have set up your
le search as described in Chap. 1. Otherwise just put qdraw.mac into your ...maxima...share\draw
as qdraw. You can just use
(%i1) load(draw)$
(%i2) load(qdraw)$
(%i3) qdraw( ex( [x,x2,x3],x,-3,3 ) )$
will produce a plot of the three explicit functions of
x and y axes,
1
2
3
20
10
-10
-20
-3
-2
-1
x, x2 , x3
You can control the vertical range of the canvas with the yr(...) function, which passes its arguments to a
draw2d entry
yrange = [y1,y2].
1.5
0.5
-0.5
-1
-1.5
-2
-3
-2
-1
Figure 2: Adding
yr(2, 2)
You can make the lines thinner or thicker than the default line width (3) by using the lw(n) option, which
only affects the quick plotting functions ex(...) and imp(...), as in
1.5
0.5
-0.5
-1
-1.5
-2
-3
-2
-1
Figure 3: Adding
lw(6)
You can place the plot key (legend) at the bottom right by using the key(bottom) option, as in:
1.5
0.5
-0.5
-1
-1.5
1
2
3
-2
-3
-2
-1
Figure 4: Adding
key(bottom)
You can remove the default grid and xy axes by adding cut(grid,xyaxes) as in:
1.5
0.5
-0.5
-1
-1.5
1
2
3
-2
-3
-2
-1
Figure 5: Adding
cut(grid, xyaxes)
You can remove the grid, axes, the key, and all the borders using cut( all ), as in:
Figure 6: Adding
cut(all)
Restoring the (default) grid and axes, we can place points (default size 3 and color black) at the intersection
points using the pts(...) option, which passes a points list to draw2d's points function:
1.5
0.5
-0.5
-1
-1.5
1
2
3
-2
-3
-2
-1
Figure 7: Adding
pts(ptlist)
We can overide the default size and color of those points by including inside the pts function the optional
ps(n) and pc(c) arguments, as in:
1.5
0.5
-0.5
-1
-1.5
1
2
3
-2
-3
-2
-1
Figure 8: Adding
We can include a key entry for the points using the pk(string) option for the pts function, as in:
1.5
0.5
-0.5
-1
1
2
3
intersections
-1.5
-2
-3
Figure 9:
-2
-1
The eps le ch5p9.eps used to get the last gure in the Tex le which is the source of this pdf le was
produced using the pic(type, lename) option to qdraw, as in:
1.5
0.5
-0.5
-1
1
2
3
4
-1.5
-2
-3
-2
-1
sin(3 x) ex/3
2
1.5
qdraw at work
1
0.5
0
-0.5
-1
1
2
3
4
-1.5
-2
-3
-2
-1
c:\windows\fonts\. Here is Maxima code to get a jpeg graphics le based on our present drawing:
(%i15) qdraw( yr(-2,2),lw(6), ex( [x,x2,x3],x,-3,3 ),
key(bottom), ex(sin(3*x)*exp(x/3),x,-3,3),
pts([ [-1,-1],[0,0],[1,1] ]) ,
label(["qdraw at work",-2.9,1.5]),
pic(jpg,"ch5p11",font("c:/windows/fonts/timesbd.ttf",20) ) );
The resulting jpeg le has thicker lines and bolder labels, so some experimentation may be called for to get the
desired result. The font le requested corresponds to times roman bold. The font le extension ttf stands for
true type fonts. If you look in the windows, fonts folder you can nd other interesting choices.
5.2
or
x u and y v .
horizontal canvas extent, and the numbers (y1,y2) determine the vertical canvas extent. Here is an example
using the single equation form:
-1
-2
-3
-3
-2
-1
sin(2 x) cos(y)
which uses the default line width = 3, the rst of the default rotating colors (blue), and, of course, the
default axes and grid. To remove the default key, we have used the cut function. Since the left hand side of
this equation will periodically return to the same numerical value in both the x and the y directions, there is no
limit to the solutions obtained by setting the left hand side equal to some numerical value between zero and
one.
This looks like one piece of a contour plot for the given function. We can add more contour lines using the
imp function by using the list of equations form:
10
-1
-2
-3
-3
-2
-1
(%i18) g : sin(2*x)*cos(y)$
(%i19) qdraw( imp( [g = 0.4,g = 0.7,g = 0.9] ,x,-3,3,y,-3,3 ) ,
cut(key) );
to achieve the same plot.
We can also use symbols like
%pi, which will evaluate to a real number, in our horizontal and vertical limit
slots, as in:
1.4
geometrical shapes look closer to reality. For the present plot we simply change the numerical values of the
imp(...) function (x1,x2) parameters:
-1
-2
-3
-4
-3
-2
-1
11
5.3
Since we are talking about contour plots, this is a natural place to give some examples of the qdraw package's
contour(...) function which has two forms:
cvals(...) form
(ignoring options):
-1
-2
-3
-4
-3
-2
-1
[grid,xaxis,yaxis,xyaxes].
-1
-2
-3
-4
-3
-2
-1
12
plots, but the drawing process takes more time, of course. For our example here, we increased this parameter
from
-1
-2
-3
-4
-3
-2
-1
1.5
0.5
-0.5
-1
-1.5
-2
-2
-1.5
-1
-0.5
0.5
13
1.5
5.4
A type of plot closely related to the contour plot is the density plot, which paints small regions of the graphics
window with a variable color chosen to highlight regions where the function of two variables takes on large
values. A completely separate density plotting function, qdensity, is supplied in the qdraw package. The
qdensity function in completely independent of the default conventions and syntax associated with the function
qdraw.
The syntax of qdensity is:
palette = [1,3,8]). To use the paletter option, the argument p can be either blue, gray, color,
or a three element list [n1,n2,n3], where (n1,n2,n3) are positive integers which select functions to apply
to
on u and v, etc.
A simple function of two variables to try is
f (x, y) = x y ,
(1,1).
(%i26) qdensity(x*y,[x,0,1,0.2],[y,0,1,0.2] )$
This produces the density plot:
14
1 at
(%i27) qdensity(x*y,[x,0,1,0.2],[y,0,1,0.2],
palette(gray) )$
we get
15
To get a ner sampling of the function, you should decrease the values of
the default palette choice with the interval choice
0.05,
(%i28) qdensity(x*y,[x,0,1,0.05],[y,0,1,0.05] )$
yields a rened density plot with
0.05
(%i29) qdensity(sin(x)*sin(y),[x,-2,2,0.05],[y,-2,2,0.05] )$
which yields
Figure 23:
sin(x) sin(y)
16
5.5
If we are willing to deal with one explicit function or expression at a time, we get more control over the plot
elements if we use the qdraw function ex1(...), which has the syntax:
required and must be in the rst four slots. The last three arguments are all optional and can be in any order.
Let's illustrate the use of ex1(...) by displaying a simple curve and the tangent and normal at one point of
2
the curve. We will use the curve y = x with the slope dy/dx = 2 x, and construct the tangent line tangent
at the point
(x0 , y0 ):
(y y0 ) = m (x x0 )
where
As we discuss in the next chapter, the normal line through the same point is
(y y0 ) = (1/m) (x x0 ).
For the point
geometry of the tangent and normal lines). The resulting plot is:
2
X^2
TANGENT
NORMAL
1.5
0.5
-0.5
-1
-1
-0.5
0.5
17
ex1(...)
1.5
2.5
Here we use ex1 to plot the rst few Bessel functions of the rst kind
0.8
0.6
0.4
0.2
-0.2
-0.4
0
10
Figure 25:
Here is a plot of
15
20
Jn (x)
J0 ( x):
(%i32) qdraw(line(0,0,50,0,lc(red),lw(2) ),
ex1(bessel_j(0, sqrt(x)),x,0,50 ,lc(blue),
lw(7),lk("J0( sqrt(x) )") ) )$
1
J0( sqrt(x) )
0.8
0.6
0.4
0.2
0
-0.2
-0.4
0
10
20
30
Figure 26:
We chose to emphasize the axis
y =0
40
50
J0 ( x)
which we will discuss later in the section on geometric gures. Placing the line element before ex1(..) causes
the curve to write over the line, rather than the reverse.
18
5.6
rather than a
Maxima function.
(%i33) g : x*exp(-x)$
(%i34) qdraw( ex1( log(g),x,0.001,10, lc(red) ),yr(-8,0)
)$
-1
-2
-3
-4
-5
-6
-7
-8
0
ln(g).
10
ln(g)
Since
is singular at
x = 0,
we have
x1 = 0.001.
g.
0.1
0.01
0.001
0.0001
0
19
10
The name log-linear plot can be used to mean x axis marked with a log scale, y axis marked with a linear
scale. Using the same function, we generate this plot by using the log(x) option to qdraw:
0.35
0.3
0.25
0.2
0.15
0.1
0.05
0
0.001
0.01
0.1
10
Scientists and engineers normally like to use a log scaled axis for a variable which varies over many powers
of ten, which is not the case for our example.
Finally, we can request log-log paper which has both axes marked with a log scale, by using the log(xy)
option to qdraw.
0.1
0.01
0.001
0.0001
0.001
0.01
0.1
20
10
5.7
In Chapter One of Maxima by Example, Section 1.5.8, we created a data le called t1.dat, which can be
downloaded from the author's webpage. We will use that data le, together with t2.dat, also available, to
illustrate making simple data plots using the qdraw functions pts(...) and errorbars(...). The syntax of pts(...)
is:
The remaining arguments are all optional and may be entered in any order following the rst required argument.
pj(lw), if present, will cause the points provided by the nested list pointlist to be
joined using a line whose width is given by the argument of pj; an example is pj(2) which would set the
pk(string) provides text for a key entry for the set of points represented by pointlist;
as example is pk("case x2").
The optional argument
Before making the data plot, let's look at the data le contents from inside Maxima:
(%i38) printfile("fit1.dat")$
1 1.8904
2 3.0708
3 3.9215
4 5.1813
5 5.9443
6 7.0156
7 7.8441
8 8.8806
9 9.8132
10 11.129
We next use Maxima's read nested list function to create a list of data points from the data le.
21
The most basic plot of this data uses the pts(...) function defaults:
11
10
9
8
7
6
5
4
3
2
1
10
We can use the qdraw functions xr(...) and yr(...) to override the default range selected by draw2d, and
decrease the point size:
14
12
10
0
0
22
10
12
Now we add color and a key string, as well as simple error bars corresponding to an assumed uncertainty
of the
14
12
10
2
fit1
0
0
10
12
1 is almost too small to see, so we thicken the error bars and add color
14
12
10
8
6
4
2
fit1
0
0
10
12
23
of the values
Here is an example:
14
12
10
8
6
4
2
fit1
0
0
10
12
We now repeat the least squares t of this data which we carried out in Chapter 1. See our discussion there
for an explanation of what we are doing here.
(%i47) display2d:false$
(%i48) pmatrix : apply( 'matrix, plist );
(%o48) matrix([1,1.8904],[2,3.0708],[3,3.9215],[4,5.1813],[5,5.9443],
[6,7.0156],[7,7.8441],[8,8.880599999999999],[9,9.8132],
[10,11.129])
(%i49) load(lsquares);
(%o49) "C:/PROGRA1/MAXIMA4.0/share/maxima/5.15.0/share/contrib/lsquares.mac"
(%i50) soln : (lsquares_estimates(pmatrix,[x,y],y=a*x+b,
[a,b]), float(%%) );
(%o50) [[a = 0.99514787679748,b = 0.99576667381004]]
(%i51) [a,b] : (fpprintprec:5, map( 'rhs, soln[1] ) )$
(%i52) [a,b];
(%o52) [0.995,0.996]
(%i53) qdraw( pts(plist,pc(blue),pk("fit1"), ps(2)), xr(0,12),yr(0,15),
key(bottom), errorbars( plist, dyl, lw(3),lc(red) ),
ex1( a*x + b,x,0,12, lc(brown),lk("linear fit") ) )$
24
14
12
10
8
6
4
2
fit1
linear fit
0
0
10
(%i54) printfile("fit2.dat");
1 0.9452
2 1.5354
3 1.9608
4 2.5907
5 2.9722
6 3.5078
7 3.9221
8 4.4403
9 4.9066
10 5.5645
(%o54) "fit2.dat"
(%i55) p2list: read_nested_list("fit2.dat");
(%o55) [[1,0.945],[2,1.5354],[3,1.9608],[4,2.5907],[5,2.9722],[6,3.5078],
[7,3.9221],[8,4.4403],[9,4.9066],[10,5.5645]]
(%i56) qdraw( pts(plist,pc(blue),pk("fit1"), ps(2)), xr(0,12),yr(0,15),
key(bottom), errorbars( plist, dyl, lw(3),lc(red) ),
ex1( a*x + b,x,0,12, lc(brown),lk("linear fit 1") ),
pts(p2list, pc(magenta),pk("fit2"),ps(2)),
errorbars( p2list,0.5,lw(3) ) )$
25
12
14
12
10
8
6
4
2
fit1
linear fit 1
fit2
0
0
10
12
We could then nd the least squares t to the data set 2 and again use the function ex1(...) to add that t to
our plot, and add any other features desired.
26
5.8
If we are willing to deal with one implicit equation of two variables at a time, we get more control over the plot
elements if we use the qdraw function imp1(...), which has the syntax:
y v.
eqn is actually a function of the pair of variables u and v, then let x u, and
The rst seven arguments are required and must be in the rst seven slots. The last three arguments are
y axes.
In the following,
eqn1 describes the rotated ellipse, eqn2 describes the rotated x axis, and eqn3
tan = 2.
(%i1)
(%i2)
(%i3)
(%i4)
eqn1 :
eqn2 :
eqn3 :
qdraw(
ELLIPSE
ROT X AXIS
ROT Y AXIS
TRANSLATED ORIGIN
-1
-2
-3
-4
-2
-1
27
As a second example with imp1 we make a simple plot based on the equation
y 3 = x2 .
3
Y^3 = X^2
2.5
1.5
0.5
-0.5
-1
-3
-2
-1
y 3 = x2
Notice that you can use hyphenated color choices (see Maxima color index) without the double quotes, or
with the double quotes.
28
5.9
The qdraw function para can be used to draw parametric plots and has the syntax
para(xofu,yofu,u,u1,u2,lw(n),lc(c),lk(string) )
where, as usual, the line width, line color, and key string are optional and can be in any order. The parameter
u can, of course, be any symbol.
A simple example, in which we use t for the parameter, and let the x coordinate corresponding to some
value of t be
sin(t), and let the y coordinate corresponding to that same value of t be sin(2 t) is:
(%i6) qdraw(xr(-1.5,2),yr(-2,2),
para(sin(t),sin(2*t),t,0,2*%pi ) ,
pts( [ [sin(%pi/8),sin(%pi/4)] ],ps(2),pc(blue),pk("t = pi/8")),
pts( [ [1,0] ],ps(2),pc(red),pk("t = pi/2")) )$
produces the plot:
t = pi/8
t = pi/2
1.5
1
0.5
0
-0.5
-1
-1.5
-2
-1.5
-1
-0.5
Figure 40:
0.5
x = sin(t), y = sin(2 t)
29
1.5
40
u=0
u = pi/2
u = pi
u = 3*pi/2
35
30
25
20
15
10
5
0
-3
-2
-1
Figure 41:
x = 2 cos(u), y = u2
30
5.10
r() = 10/.
t = 1 rad
t = 2 rad
-2
-4
-2
31
r = 10/
5.11
line(0,0,1,1,lc(blue),lw(6),lk("radius") )
(1, 1) in blue with line width 6 and with a key entry with the text 'radius'.
width 3, and no key entry.
to
0.8
0.6
0.4
0.2
0
0
0.2
0.4
0.6
0.8
Adding some options and extending the canvas range in both directions
1.5
0.5
radius
point
0
0
0.5
1.5
32
(0, 0)
Here we dene a Maxima function doplot1(n) in a le doplot1.mac which has the following contents:
/* file doplot1.mac */
disp("doplot1(nlw)")$
doplot1(nlw) := block([cc,qlist,x,val,i ],
/* list of 20 single name colors */
cc : [aquamarine,beige,blue,brown,cyan,gold,goldenrod,green,khaki,
magenta,orange,pink,plum,purple,red,salmon,skyblue,turquoise,
violet,yellow ],
qlist : [ xr(-3.3,3) ],
for i thru length(cc) do (
x : -3.3 + 0.3*i,
val : line( x,-1,x,1, lc( cc[i] ),lw(nlw) ),
qlist : append(qlist, [val] )
),
qlist : append( qlist,[ cut(all) ] ),
apply('qdraw, qlist)
)$
Here is a record of loading and using the function dened to produce a series of vertical colored lines.
(%i11) load(doplot1);
(%o11)
(%i12) doplot1(20);
doplot1(nlw)
c:/work2/doplot1.mac
which produces the graphic (note use of cut(all) to get a blank canvas):
33
5.12
optional; without them the rectangle is drawn in black with line thickness 3 and with no ll color. An example
is
rect(0,0,1,1,lc(brown),lw(2),fill(khaki) )
1.5
0.5
-0.5
-1
-1
-0.5
0.5
1.5
1.5
0.5
-0.5
-1
-1
-0.5
0.5
1.5
34
5.13
in which pointlist has the same form as when used with pts:
and the arguments lc, lw, and ll are optional and can be in any order after pointlist. The last point in the list
will be automatically connectd to the rst.
The default call to poly has color black, line width 3 and no ll color.
35
) )$
Next we create the work le doplot2.mac which contains the following Maxima function which will draw
eighteen right triangles in various colors:
/* eighteen triangles */
disp("doplot2()")$
print("eighteen colored triangles")$
doplot2() :=
block([cc, qlist,x1,x2,y1,y2,i,val ],
cc : [aquamarine,beige,blue,brown,cyan,gold,goldenrod,green,khaki,
magenta,orange,pink,plum,purple,red,salmon,skyblue,turquoise,
violet,yellow ],
qlist : [ xr(-3.3,3.3), yr(-3.3,3.3) ],
/* top row of triangles */
y1 : 1,
y2 : 3,
for i:0 thru 5 do (
x1 : -3 + i,
x2 : x1 + 1,
val : poly( [ [x1,y1],[x2,y1],[x1,y2]], fill( cc[i+1] ) ),
qlist : append(qlist, [val ] )
),
/* middle row of triangles */
y1 : -1,
y2 : 1,
for i:0 thru 5 do (
x1 : -3 + i,
x2 : x1 + 1,
val : poly( [ [x1,y1],[x1,y2],[x2,y2]], fill( cc[i+7] ) ),
qlist : append(qlist, [val ] )
),
36
(%i17) load(doplot2);
eighteen colored triangles
(%o17)
(%i18) doplot2();
doplot2()
c:/work2/doplot2.mac
For homework, use poly and pts to draw the following gure. (Hint: you should also use xr(...) ).
37
5.14
entered in any order after the required rst three arguments. This object will not look like a circle unless you
take care to make the horizontal extent of the canvas about
yr(...) ).
Here is the default circle in black, with line width 3, and no ll color.
1.5
0.5
-0.5
-1
-1.5
-2
-2
-1.5
-1
-0.5
0.5
1.5
By using xr(...) and yr(...) we try for a round circle and also add what should be a 45 degree line.
(%i20) qdraw(xr(-2.1,2.1),yr(-1.5,1.5),cut(all),
circle(0,0,1,lw(5),lc(brown),fill(khaki) ),
line(-1.5,-1.5,1.5,1.5,lw(8), lc(red) ),
key(bottom) )$
with the result:
38
and
The line painted over the circle because of the order of the arguments to qdraw. If we reverse the order,
drawing the line before the circle:
(%i21) qdraw(xr(-2.1,2.1),yr(-1.5,1.5),cut(all),
line(-1.5,-1.5,1.5,1.5,lw(8),lc(red) ),
circle(0,0,1,lw(8),lc(brown),fill(khaki) ),
key(bottom) )$
then the circle color will hide the line:
The last three arguments are optional. The default is the outline of an ellipse for the specied angular range
in color black, line width 3, and no ll color.
Here is the default behavior:
-1
-2
-3
-4
-3
-2
-1
39
5.15
vector([x,y],[dx,dy],ha(thdeg),hb(v),hl(v),ht(t),lw(n),lc(c),lk(string) )
which draws a vector with components [dx,dy] starting at [x,y].
The rst two list arguments are required, all others are optional and can be entered in any order after the rst
two required arguments.
The default head angle is 30 deg; change to 45 deg using ha(45) for example.
The default head both value is f for false; use hb(t) to set it to true, and hb(f) to return to false.
The default head length is 0.5; use hl(0.7) to change to 0.7.
The default head type is nolled; use ht(e) for empty, ht(f) for lled, and ht(n) to change back to
nolled.
Once one of the head properties has been changed in a call to vector, the next calls to vector assume the
change is still in force.
The default line width is 3; use lw(5) to change to 5.
The default line color is black; use lc(brown) to change to brown.
The default is no key string; use lk(A1), for example, to create a text string for the key.
40
2
1.5
1
0.5
0
-0.5
-1
-1.5
-2
-2
-1.5
-1
-0.5
0.5
1.5
(%i25) qdraw(xr(-2,2),yr(-2,2),
vector([-1,-1],[2,2],lw(5),lc(brown),lk("vec 1")),
key(bottom) )$
which looks like:
2
1.5
1
0.5
0
-0.5
-1
-1.5
vec 1
-2
-2
-1.5
-1
-0.5
0.5
41
1.5
Next we can alter the head properties, but let's also make this vector shorter.
head type to empty,
We use
angle to
ht(e)
to set
45 degrees.
(%i26) qdraw(xr(-2,2),yr(-2,2),
vector([0,0],[1,1],lw(5),lc(blue),lk("vec 1"),
ht(e),hb(t),ha(45) ), key(bottom) )$
which produces:
2
1.5
1
0.5
0
-0.5
-1
-1.5
vec 1
-2
-2
-1.5
-1
-0.5
0.5
1.5
Once you invoke the head properties options, the new settings are used on your next calls to vector (unless
you deliberately change them). Here is an example of that memory feature at work:
(%i27) qdraw(xr(-2.8,2.8),yr(-2,2),
vector([0,0],[1,1],lw(5),lc(blue),lk("vec 1"),
ht(e),hb(t),ha(45) ),
vector([0,0],[-1,-1],lw(5),lc(red),lk("vec 2")),
key(bottom) )$
and we also used the x-range setting to get the geometry closer to reality, with the result:
2
1.5
1
0.5
0
-0.5
-1
-1.5
vec 1
vec 2
-2
-2
-1
42
5.16
(%i28) qdraw(xr(-2.8,2.8),yr(-2,2),
arrowhead(1.5,0,180,.3),arrowhead(0,1,270,.3),
arrowhead(-1.5,0,0,.3),arrowhead(0,-1,90,.3) )$
2
1.5
1
0.5
0
-0.5
-1
-1.5
-2
-2
-1
5.17
5.17.1
Here we combine line(..), ellipse, arrowhead and label, using the enhanced postscript abilities of draw2d's
terminal = eps option, which became effective with the June 11, 2008 draw package update. This update
includes an extension of the terminal = eps abilities to include local conversion of font properties and
the use of Greek and some math characters. As of the writing of this section, it was necessary to download this
update from the webpage
http://maxima.cvs.sourceforge.net/maxima/maxima/share/draw/draw.lisp. On that
webpage you will see Log of /maxima/share/draw/draw.lisp, and the top entry is
Revision 1.31 - (view) (download) (annotate) - [select for diffs]
Wed Jun 11 18:19:55 2008 UTC. Click on the download link, and the text of draw.lisp will appear
in your browser with the top looking like:
43
;;;
COPYRIGHT NOTICE
;;;
;;; Copyright (C) 2007 Mario Rodriguez Riotorto
;;;
;;; This program is free software; you can redistribute
;;; it and/or modify it under the terms of the
;;; ........................ etc
This is a program written in the Lisp language, and down near the bottom is a series of lines which provide for
the enhanced postscript behavior:
to replace the old draw.lisp (which you could rename prior to the save as ), then you can use the label syntax
inside strings as shown in the following.
(%i29) qdraw(xr(0,2.8),yr(0,2),
line(0,0,2.8,0,lw(2)),
line(0,0,2,2,lc(blue),lw(8) ),
ellipse(0,0,1,1,0,45 ),
arrowhead(0.707,0.707,135,0.15),
label(["{/=36 {/Symbol q \\254 } The Incline Angle}",1,0.4]),
cut(all),
pic(eps,"ch5p52" ) );
The result looks like:
http://www.telefonica.net/web2/biomates/maxima/gpdraw/ps/ps_guide.ps
although
the examples of using the characters works for me only if I use two back slashes, as in the example just shown,
44
\\254 inside the {/Symbol } structure produces the leftward pointing arrow (thanks to the
draw package developer, Mario Rodriguez Riotorto, for the enhanced postscript abilities, and for aiding my
understanding of how to use these features). An example of creating text for a label which includes the integral
sign and Greek letters is given on the webpage:
http://www.telefonica.net/web2/biomates/maxima/gpdraw/ps/.
The entry {/Symbol q } by itself would produce just the Greek letter . Wrapping the text entry in the
structure {/=36
} accepts the default font type and sets the font size to 36 for the text inside the pair of
braces.
Here we make a lower case Latin to Greek conversion reminder using four instances of label, although we
could alternatively have used the syntax
(%i30) qdraw(xr(-3,3),yr(-2,2),label_align(c),
label( ["{/=48 a b c d e f g h i j k l m}",0,1.5] ),
label( ["{/Symbol=48 a b c d e f g h i j k l m}",0,0.5] ),
label( ["{/=48 n o p q r s t u v w x y z}",0,-.5] ),
label( ["{/Symbol=48 n o p q r s t u v w x y z}",0,-1.5] ),
cut(all), pic(eps,"ch5p53") )$
Note how we increase the font size of the latin alphabet
abcdefghijklm
nopqrstuvwxyz
(%i31) qdraw(xr(-3,3),yr(-2,2),label_align(c),
label( ["{/=48 A B C D E F G H I J K L M}",0,1.5] ),
label( ["{/Symbol=48 A B C D E F G H I J K L M}",0,0.5] ),
label( ["{/=48 N O P Q R S T U V W X Y Z}",0,-.5] ),
label( ["{/Symbol=48 N O P Q R S T U V W X Y Z}",0,-1.5] ),
cut(all), pic(eps,"ch5p54") )$
You can see the resulting gure on the next page.
{/Symbol=36 \\abc
\\243 (less than or equal )
\\245 (innity symbol)
\\253 (double ended arrow)
\\254 (left arrow)
\\256 (right arrow)
or as
45
etc }
ABCDEFGHIJKLM
NOPQRSTUVWXYZ
Here we use label to illustrate these possible symbols you can use:
46
5.17.2
in a jpeg le or a png le by using the Greek font les in the
(%i35) qdraw(xr(0,2.8),yr(0,2),
line(0,0,2.8,0),
line(0,0,2,2,lc(blue),lw(5) ),
ellipse(0,0,1,1,0,45 ),
arrowhead(0.707,0.707,135,0.15),
label(["q",1,0.4]), cut(all),
pic(jpg,"ch5p52p",font("c:/windows/fonts/grii.ttf",36)) );
(%i36) qdraw(xr(-3,3),yr(-2,2),
label(["a b c d e f g h i j k l m",-2.5,1.5],
["n o p q r s t u v w x y z",-2.5,0.5],
["A B C D E F G H I J K L M",-2.5,-0.5],
["N O P Q R S T U V W X Y Z",-2.5,-1.5] ),
cut(all),
pic(png,"ch5p60",font("c:/windows/fonts/grii.ttf",24)) );
47
After conversion of the png to an eps graphics le using Cygwin's convert function, we get:
5.17.3
In the default Windows Gnuplot console mode, you can convert some Latin letters to Greek as follows:
(%i37) qdraw(xr(0,2.8),yr(0,2),
line(0,0,2.8,0),
line(0,0,2,2,lc(blue),lw(5) ),
ellipse(0,0,1,1,0,45 ),
arrowhead(0.707,0.707,135,0.15),
label(["q",1,0.4]), cut(all) );
When the console graphics window appears, right click on the upper left corner icon and select Options, Choose
Font. In the Font panels, choose Graecall font, regular from the middle panel, and size 36 from the right panel
and click ok. The English letter q (lower case) is then converted to the Greek lower case theta. Use the
Gnuplot window menu again to save the resulting image to the clipboard, and open an image viewer. I use the
freely available Infanview. If you use View, Paste, the clipboard image appears inside Infanview, and you can
save the image as a jpeg le in your choice of folder. Since I am using eps graphics les for this latex le, I
converted the jpg to eps using Cygwin's convert function:
convert name.jpg
name.eps.
48
Unfortunately, saving the Gnuplot window image to the Window's clipboard also saves the current cursor
position, which is not desirable.
5.18
You can use the qdraw function more(...), containing any legal draw2d elements, as we illustrate by adding a
label to the x-axis and a title. We focus here on producing an eps graphics le to display the enhanced ability
to show subscripts and superscripts.
xn
intersections of x, x2, x3
8
6
4
2
0
-2
-4
-6
-8
x2
x3
-2
-1.5
-1
-0.5
0
0.5
X AXIS
49
1.5
5.19
5.19.1
The le qdraw.mac is a text le which you can modify with a good text editor such as notepad2. This Maxima
code is heavily commented as an aid to passing on some Maxima language programming examples.
You
can get some experience with the Maxima programming language elements by copying the le qdraw.mac to
another name, say myqdraw.mac, and use that copy to make modications to the code which might interest
you. By frequently loading in the modied le with
Placing a comma
you may nd it useful to insert some special debug printouts, such as
for i thru n do (
job1,
job2,
job3,
print(" i = ",i," blank = ",blank)
/* end do loop */
),
...program continues...
When you are nished debugging a section, you either will comment out the debug printout or simply delete it
to clean up the code. If you are not fully awake, you might then load into Maxima
for i thru n do (
job1,
job2,
job3,
/* end do loop */
),
...program continues...
and, of course, Maxima will object, since that extra comma no longer makes sense.
It is crucial to use a good text editor which will balance parentheses, brackets, and braces to minimize
parentheses etc errors.
If you look at the general structure of qdraw, you will see that most of the real work is done by qdraw1.
If you call qdraw1 instead of qdraw, you will be presented with a rather long list of elements which are
understood by draw2d. Even if you use qdraw, you will see the same long list wrapped by draw2d if you
have not loaded the draw package.
One feature you should look at is how a function which takes an arbitrary number of arguments, depending
on the user (as does the function draw2d), is dened. If this seems strange to you, experiment with a toy
function having a variable number of arguments, and use printouts inside the function to see what Maxima is
doing.
50
5.19.2
XMaxima Tips
It is useful to rst try out a small code idea directly in XMaxima, even if the code is ten or fteen lines long,
since the XMaxima interface has been greatly improved.
Alt-p to enter your previous code, and immediately backspace over the nal ); or )$.
up to an area where you want to add a new line of code, and with the cursor placed just after a comma, press
ENTER to create a new (blank) line. Since the block of code has not been properly concluded with either a );
or )$, Maxima will not try to run with the version you are working on when you press ENTER. Once you
have made the changes you want, cursor your way to the end and put back the correct ending and then pressing
HOME to put the cursor at the beginning of the current line, then PAGEUP or CNTRL-HOME to get up to the
top fast, then drag over the code (don't include the (%i5) part) to the end but not to the concluding ); or )$.
You can hold down the SHIFT key and use the right (and left) cursor key to help you select a region to copy.
Then press CNTRL-C to copy the selected code to Window's clipboard. Then press CTRL-END to have the
cursor move to the bottom of your workspace where XMaxima is waiting for your next input. Press CNTRL-V
to paste your selection. If the selection extends over multiple lines, use the down cursor key to nd the end
of the selection which should be without the proper code ending
); or )$.
and can cursor your way around the code and make any changes without danger of XMaxima pre-emptively
sending your work to the computing engine until you go to that end and provide the proper ending.
5.19.3
Suggested Projects
You will have noticed that we used the qdraw function more in order to insert axis labels and a title into
our plot. Design qdraw functions
Place
them in the scan 3 section of qdraw and try them out. You will need to pay attention to how new elements get
passed to draw2d. In particular, look at the list
Ctrl-f ) to see how that list is constructed based on the user input.
A second small project would be to add a line type option for the qdraw function line. My experience
is that setting
line_type = dots
console window, produces a nely dotted line for jpeg and png image les, and produces a dashed line with
eps image les.
tax
Your addition to qdraw should follow the present style, so the user would use the syn-
solid or dots).
A third small project would be to design a function triangle for qdraw, including the options which are
presently in poly.
A fourth small project would be to include the option cbox(..) in the qdensity function. The present default
is to include the colorbox key next to the density plot, but if the user entered
qdensity(....,cbox(f) )
5.20
Acknowledgements
The author would like to thank Mario Rodriguez Riotorto, the creator of Maxima's draw graphics interface
to Gnuplot, for his encouragement and advice at crucial stages in the development of the qdraw interface to
draw2d. The serious graphics user should spend time with the many powerful features of the draw package,
and the examples provided on the draw webpages,
http://www.telefonica.net/web2/biomates/maxima/gpdraw/.
These examples go far beyond the simple graphics in this chapter. The recent updating of the draw package
to allow use of Gnuplot's enhanced postscript features makes Maxima a more attractive tool for the creation of
educational diagrams.
52
Preface
COPYING AND DISTRIBUTION POLICY
This document is part of a series of notes titled
"Maxima by Example" and is made available
via the authors webpage http://www.csulb.edu/woollett/
to aid new users of the Maxima computer algebra system.
NON-PROFIT PRINTING AND DISTRIBUTION IS PERMITTED.
You may make copies of this document and distribute them
to others as long as you charge no more than the costs of printing.
These notes (with some modifications) will be published in book form
eventually via Lulu.com in an arrangement which will continue
to allow unlimited free download of the pdf files as well as the option
of ordering a low cost paperbound version of these notes.
Feedback from readers is the best way for this series of notes to become more helpful to new users of Maxima. All
comments and suggestions for improvements will be appreciated and carefully considered.
LOADING FILES
The defaults allow you to use the brief version load(fft) to load in the
Maxima file fft.lisp.
To load in your own file, such as qxxx.mac
using the brief version load(qxxx), you either need to place
qxxx.mac in one of the folders Maxima searches by default, or
else put a line like:
file_search_maxima : append(["c:/work2/###.{mac,mc}"],file_search_maxima )$
in your personal startup file maxima-init.mac (see later in this chapter
for more information about this).
Otherwise you need to provide a complete path in double quotes,
as in load("c:/work2/qxxx.mac"),
We always use the brief load version in our examples, which are generated
using the XMaxima graphics interface on a Windows XP computer, and copied
into a fancy verbatim environment in a latex file which uses the fancyvrb
and color packages.
6 DIFFERENTIAL CALCULUS
6 Differential Calculus
The methods of calculus lie at the heart of the physical sciences and engineering.
The student of calculus needs to take charge of his or her own understanding, taking the subject apart and putting it back
together again in a way that makes logical sense. The best way to learn any subject is to work through a large collection
of problems. The more problems you work on your own, the more you own the subject. Maxima can help you make
faster progress, if you are just learning calculus.
For those who are already calculus savvy, the examples in this chapter will offer an opportunity to see some Maxima tools
in the context of very simple examples, but you will likely be thinking about much harder problems you want to solve as
you see these tools used here.
After examples of using diff and gradef, we present examples of finding the critical and inflection points of plane
curves defined by an explicit function.
We then present examples of calculating and plotting the tangent and normal to a point on a curve, first for explicit functions and then for implicit functions.
We also have two examples of finding the maximum or minimum of a function of two variables.
We then present several examples of using Maximas powerful limit function, followed by several examples of using
taylor.
The next section shows examples of using the vector calculus functions (as well as cross product) in the package
vcalc.mac, developed by the author and available on his webpage with this chapter, to calculate the gradient, divergence, curl, and Laplacian in cartesian, cylindrical, and spherical polar coordinate systems. An example of using this
package would be curl([r*cos(theta),0,0]); (if the current coordinate system has already been changed to
spherical polar) or curl([r*cos(theta),0,0], s(r,theta,phi) ); if the coordinate system needs to be
shifted to spherical polar from either cartesian (the starting default) or cylindrical.
The order of list vector components corresponds to the order of the arguments in s(r,theta,phi). The Maxima
output is the list of the vector curl components in the current coordinate system, in this case [0, 0, sin(theta)]
plus a reminder to the user of what the current coordinate system is and what symbols are currently being used for the
independent variables.
Thus the syntax is based on lists and is similar (although better!) than Mathematicas syntax.
There is a separate function to change the current coordinate system. To set the use of cylindrical coordinates (rho,phi,z):
setcoord( cy(rho,phi,z) );
and to set cylindrical coordinates (r,t,z):
setcoord( cy(r,t,z) );
The package vcalc.mac also contains the plotting function plotderiv which is useful for automating the plotting
of a function and its first n derivatives.
The next two sections dicuss the use of the batch file mode of problem solving by presenting Maxima based derivations
of the form of the gradient, divergence, curl, and Laplacian by starting with the cartesian forms and changing variables to
(separately) cylindrical and spherical polar coordinates. (The batch files used are cylinder.mac and sphere.mac.)
These two sections show Maximas implementation of the calculus chain rule at work with use of both depends and
gradef.
6 DIFFERENTIAL CALCULUS
n x
(n - 2) (n - 1) n x
Here we take the derivative (with respect to x) of an expression depending on both x and y.
(%i3) diff(x2 + y2,x);
(%o3)
2 x
You can differentiate with respect to any expression that does not involve explicit mathematical operations.
(%i4) diff( x[1]2 + x[2]2, x[1] );
(%o4)
2 x
1
Note that x1 is Maximas way of pretty printing x[1]. We can use the grind function to display the output %o4 in
the non-pretty print mode (what would have been returned if we had set the display2d switch to false).
(%i5) grind(%)$
2*x[1]$
(%i6) display2d$
Note the dollar sign grind adds to the end of its output.
Finally, an example of using one invocation of diff to differentiate with respect to more than one variable:
(%i7) diff(x2*y3,x,1,y,2);
(%o7)
12 x y
6 DIFFERENTIAL CALCULUS
d f (x) =
d f (x)
dx
dx
(6.1)
In the first example below, we calculate the differential of the expression x2 , that is, the derivative of the expression (with
respect to the variable x) multiplied by the differential of the independent variable x, d x. Maxima uses del(x) for
the differential of x, a small increment of x.
(%i1) diff(x2);
(%o1)
2 x del(x)
If the expression contains two parameters x and y, then the total differential is equivalent to the Maxima expression
diff(expr,x)*del(x) + diff(expr,y)*del(y) ,
which generates (using conventional notation):
d f (x, y) =
f (x, y)
x
dx +
y
f (x, y)
y
d y.
(6.2)
We can use the subst function to replace, say del(x), by anything else:
(%i4) subst(del(x) = dx, %o1);
(%o4)
2 dx x
(%i5) subst([del(x)= dx, del(y) = dy, del(a) = da],%o3 );
2 3
3
2 2
(%o5)
da x y + 2 a dx x y + 3 a dy x y
You can use the declare function to prevent some of the symbols from being treated as variables when calculating the
total differential:
(%i6) declare (a, constant)$
(%i7) diff(a*x2*y3);
2 2
3
(%o7)
3 a x y del(y) + 2 a x y del(x)
(%i8) declare([b,c],constant)$
(%i9) diff( a*x3 + b*x2 + c*x );
2
(%o9)
(3 a x + 2 b x + c) del(x)
(%i10) properties(a);
(%o10)
[database info, kind(a, constant)]
(%i11) propvars(constant);
(%o11)
[a, b, c]
6 DIFFERENTIAL CALCULUS
(%i12) kill(a,b,c)$
(%i13) propvars(constant);
(%o13)
(%i14) diff(a*x);
(%o14)
[]
a del(x) + x del(a)
We can map diff on to a list of functions of x, say, and divide by del(x), to generate a list of derivatives, as in
(%i15) map(diff,[sin(x),cos(x),tan(x) ] )/del(x);
2
(%o15)
[cos(x), - sin(x), sec (x)]
(%i16) map(diff,%)/del(x);
2
(%o16)
[- sin(x), - cos(x), 2 sec (x) tan(x)]
(6.3)
(6.4)
(6.5)
The default Maxima result for the first derivatives of sin x, cos x, and tan x is:
(%i1) map(diff,[sin(x),cos(x),tan(x)] )/del(x);
(%o1)
2
[cos(x), - sin(x), sec (x)]
Before using gradef to alter the return value of diff for these three functions, lets check that Maxima agrees with the
trig identities displayed above. Variable amounts of expression simplification are needed to get what we want.
(%i2) trigsimp( 1 + tan(x)2 );
1
------2
cos (x)
(%i3) ( trigsimp( 2*tan(x/2)/(1 + tan(x/2)2) ), trigreduce(%%) );
(%o3)
sin(x)
(%i4) ( trigsimp( (1-tan(x/2)2)/(1 + tan(x/2)2) ),
trigreduce(%%), expand(%%) );
(%o4)
cos(x)
(%o2)
Recall that trigsimp will convert tan, sec, etc to sin and cos of the same argument. Recall also that trigreduce
will convert an expression containing cos(x/2) and sin(x/2) into an expression containing cos(x) and sin(x).
Finally, remembering that sec x = 1/cos x, we see that Maxima has passed the test.
6 DIFFERENTIAL CALCULUS
Now lets use gradef to express the derivatives in terms of tan x and tan(x/2):
(%i5) gradef(tan(x), 1 + tan(x)2 );
(%o5)
tan(x)
(%i6) gradef(sin(x),(1-tan(x/2)2 )/(1 + tan(x/2)2 ) );
(%o6)
sin(x)
(%i7) gradef(cos(x), -2*tan(x/2)/(1 + tan(x/2)2 ) );
(%o7)
cos(x)
f 0 (x)
f 0 (x)
changes from + to ,
changes from to + ,
f 00 (a) < 0
f 00 (a) > 0
If f (x) is a function with a continuous second derivative, and if, as x increases through the value a, f 00 (x) changes sign,
then the plot of f (x) has an inflection point at x = a and f 00 (a) = 0. The inflection point requirement that f 00 (x) changes
sign at x = a is equivalent to f 000 (a) 6= 0. We consider some simple examples taken from Sect. 126 of Analytic Geometry
and Calculus, by Lloyd L. Smail, Appleton-Century-Crofts, N.Y., 1953 (a reference which dates the writer of these
notes!).
6.2.1 Example 1: A Polynomial
To find the maxima and minima of the function f (x) = 2 x3 3 x2 12 x + 13, we use an expression (called g)
rather than a Maxima function. We use gp (g prime) for the first derivative, and gpp (g double prime) as notation for the
second derivative. Since we will want to make some simple plots, we use the package qdraw, available on the authors
webpage, and discussed in detail in chapter five of these notes.
(%i1) load(draw)$
(%i2) load(qdraw);
qdraw(...), qdensity(...), syntax: type qdraw();
(%o2)
c:/work2/qdraw.mac
(%i3) g : 2*x3 - 3*x2 - 12*x + 13$
(%i4) gf : factor(g);
2
(%o4)
(x - 1) (2 x - x - 13)
(%i5) gp : diff(g,x);
2
(%o5)
6 x - 6 x - 12
(%i6) gpf : factor(gp);
(%o6)
6 (x - 2) (x + 1)
(%i7) gpp : diff(gp,x);
(%o7)
12 x - 6
(%i8) qdraw( ex(g,x,-4,4), key(bottom) )$
6 DIFFERENTIAL CALCULUS
Since the coefficients of the given polynomial are integral, we have tried out factor on both the given expression
and its first derivative. We see from output %o6 that the first derivative vanishes when x = -1, 2 . We can confirm
these critical points of the given function by using qdraw with the quick plotting argument ex, which gives us the plot:
40
20
0
-20
-40
-60
-80
-100
1
-4
-3
-2
-1
[x = 2, x = - 1]
[20, - 18]
[- 7, 18]
We next look for the inflection points, the points where the curvature changes sign, which is equivalent to the points
where the second derivative vanishes.
(%i12) solve(gpp=0);
(%o12)
(%i13) g,x=0.5;
(%o13)
1
[x = -]
2
6.5
We have found one inflection point, that is a point on a smooth curve where the curve changes from concave downward
to concave upward, or visa versa (in this case the former).
We next plot g, gp, gpp together.
(%i14) qdraw2( ex([g,gp,gpp],x,-3,3), key(bottom),
pts([[-1,20]],ps(2),pc(magenta),pk("MAX") ),
pts([[2,-7]],ps(2),pc(green),pk("MIN") ),
pts([[0.5, 6.5]],ps(2),pk("INFLECTION POINT") ) )$
6 DIFFERENTIAL CALCULUS
60
40
20
0
1
2
3
MAX
MIN
INFLECTION POINT
-20
-40
-3
-2
-1
6 DIFFERENTIAL CALCULUS
10
We have provided two versions of this function, the first version commented out. If the expression to be plotted is a
very complicated function and you are concerned with computing time, you can somewhat improve the efficiency of
plotderiv by introducing a hashed array called aa[j], say, to be able to simply differentiate the previous derivative expression. That is the point of version 2 which is not commented out.
We have added the line display(plist) to print a list containing the expression as well as all the derivatives requested. We test plotderiv on the expression u3. Both draw.lisp and qdraw.mac must be loaded for this to
work.
(%i15) load(vcalc)$
vcalc.mac:
for syntax, type: vcalc_syntax();
CAUTION: global variables set and used in this package:
hhh1, hhh2, hhh3, uuu1, uuu2, uuu3, nnnsys
(%i16) plotderiv(u3,u,-3,3,-27,27,4)$
3
2
plist = [u , 3 u , 6 u, 6, 0]
20
10
-10
1
2
3
4
5
-20
-3
-2
-1
Figure 3: 1: u3 , 2: 3 u2 , 3: 6 u, 4: 6, 5: 0
6 DIFFERENTIAL CALCULUS
11
-2
1
2
3
-4
-1
-0.5
0.5
1.5
2.5
Figure 4: 1: f = 3 x4 4 x3 , 2: f 0 , 3: f 00
We have inflection points at x = 0, 2/3 since the second derivative is zero at both points and changes sign as we
follow the curve through those points. The curve changes from concave up to concave down passing through x = 0,
and changes from concave down to concave up passing through x = 2/3. The following provides confirmation of our
inferences from the plot:
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%o22)
(%i23)
(%o23)
(%i24)
(%o24)
(%i25)
(%o25)
(%i26)
(%o26)
g:3*x4 - 4*x3$
g1: diff(g,x)$
g2 : diff(g,x,2)$
g3 : diff(g,x,3)$
x1 : solve(g1=0);
[x = 0, x = 1]
gcrit : makelist(subst(x1[i],g),i,1,2);
[0, - 1]
x2 : solve(g2=0);
2
[x = -, x = 0]
3
ginflec : makelist( subst(x2[i],g ),i,1,2 );
16
[- --, 0]
27
g3inflec : makelist( subst(x2[i],g3),i,1,2 );
[24, - 24]
We have critical points where the first derivative vanishes at x = 0, 1. Since the first derivative does not change sign as
the curve passes through the point x = 0, that point is neither a maximum nor a mimimum point. The point x = 1 is a
minimum point since the first derivative changes sign from negative to positive as the curve passes through that point.
6 DIFFERENTIAL CALCULUS
12
2
1.5
1
0.5
0
-0.5
-1
-1.5
1
2
-2
-2
-1.5
-1
-0.5
0.5
1.5
(%i29) limit(gp,x,0,plus);
(%o29)
(%i30) limit(gp,x,0,minus);
(%o30)
(%i31) limit(gp,x,0);
(%o31)
2
-----1/3
3 x
inf
minf
und
The most frequent use of the Maxima limit function has the syntax
Function: limit (expr, x, val, dir)
Function: limit (expr, x, val)
The first form computes the limit of expr as the real variable x approaches the value val from the direction
dir. dir may have the value plus for a limit from above, minus for a limit from below.
In the second form, dir is omitted, implying a two-sided limit is to be computed.
limit uses the following special symbols: inf (positive infinity) and minf (negative infinity). On output
it may also use und (undefined), ind (indefinite but bounded) and infinity (complex infinity).
Returning to our example, if we ignore the point x = 0, the slope is always decreasing, so the second derivative is always
negative.
6 DIFFERENTIAL CALCULUS
13
[tx, ty]
[nx, ny]
Two vectors are orthogonal if the dot product is zero. A simple example will illustrate this general property. Consider
the pair of unit vectors: ivec = [1,0], parallel to the positive x axis and jvec = [0,1], parallel to the positive y
axis.
(%i3) ivec : [1,0]$
(%i4) jvec : [0,1]$
(%i5) ivec . jvec;
(%o5)
Since Maxima allows us to use a period to find the dot product (inner product) of two lists (two vectors), we will ensure
that the normal vector is at right angles to the tangent vector by requiring nvec . tvec = 0
(%i6) eqn : nvec . tvec = 0;
(%o6)
ny ty + nx tx = 0
(%i7) eqn : ( eqn/(nx*ty), expand(%%) );
tx
ny
(%o7)
-- + -- = 0
ty
nx
We represent the normal (the line perpendicular to the tangent line) at the point (x0 , y0 ) as y = mn (x x0 ) + y0 ,
where mn is the slope of the normal line: mn = ny/nx = - (1/(ty/tx)) = -1/m .
In words, the slope of the normal line is the negative reciprocal of the slope of the tangent line.
Thus the equation of the local normal to the curve at the point (x0 , y0 ) can be written as y = (x x0 )/m + y0 ,
where m is the slope of the local tangent.
6 DIFFERENTIAL CALCULUS
14
6.3.1 Example 1: x2
As an easy first example, lets use the function f (x) = x2 and construct the tangent line and normal line to this plane
curve at the point x = 1, y = f(1) = 1. (We have discussed this same example in Ch. 5). The first derivative is
2 x, and its value at x = 1 is 2. Thus the equation of the local tangent to the curve at (x,y) = (1,1) is y = 2 x 1.
The equation of the local normal at the same point is y = x/2 + 3/2.
We will plot the curve y = x2 , the local tangent, and the local normal together. Special care is needed to get the horizontal
canvas width about 1.4 times the vertical height to achieve a geometrically correct plot; otherwise the normal line
would not cross the tangent line at right angles.
(%i8) qdraw( ex([x2,2*x-1,-x/2+3/2],x,-1.4,2.8), yr(-1,2) ,
pts( [ [1,1]],ps(2) ) )$
1
2
3
1.5
0.5
-0.5
-1
-1
-0.5
0.5
1.5
2.5
1
x
so the slope of our curve (and the tangent) at the chosen point is 1/2, and the slope of the local normal is -2.
The equation of the tangent is then (y ln(2)) = (1/2) (x 2), or y = x/2 0.307. The equation of the normal
6 DIFFERENTIAL CALCULUS
15
is (y ln(2)) = 2 (x 2), or y = 2 x + 4.693. In order to get a decent plot, we need to stay away from the singular point x = 0, so we start the plot with x a small positive number. We choose to use the x-axis range (0.1, 4), then
x = 3.9. Since we want the canvas width x 1.4 y, we need y = 2.786, which is satisfied if we choose the
y-axis range to be (1, 1.786).
(%i10) qdraw(key(bottom), yr(-1,1.786),
ex([log(x), x/2 - 0.307, -2*x + 4.693],x,0.1,4),
pts( [ [2,0.693]],ps(2) ) );
1.5
0.5
-0.5
1
2
3
-1
0
0.5
1.5
2.5
3.5
= 0,
f (a, b)
y
=0
(6.6)
in which the notation means first take the partial derivatives for arbitrary x and y and then evaluate the resulting derivatives at the point (x, y) = (a, b).
Examples show that these two conditions (I) do not guarantee that the function actually takes on an extreme value at the
point (a, b), although in many practical problems the existence and nature of an extreme value is often evident from
the problem itself and no extra test is needed; all that is needed is the location of the extreme value.
If condition (I) is satisfied and if, in addition, at the point (a, b) we have (II):
2 f
x2
2 f
y2
2 f
x y
2
>0
(6.7)
then f (x, y) will have a maximum value or a minimum value given by f (a, b) according as 2 f / x2
( or 2 f / y 2 ) is negative or positive for x = a, y = b. If condition (I) holds and < 0 then f (a, b) is neither a
maximum nor a minimum; if = 0 the test fails to give any information.
6 DIFFERENTIAL CALCULUS
16
v = x y z
v
[z = ---]
x y
+ y*z + z*x) ), expand(%%) );
2 v
2 v
2 x y + --- + --y
x
2 v
2 y - --- = 0
2
x
Since the physical solutions must be real, the first sublist is the physical solution which implies the cubical shape as the
answer.
6 DIFFERENTIAL CALCULUS
17
An alternative solution path is to solve eq2 above for y as a function of x and v and use this to eliminate y from
eqn3.
(%i7) soly : solve(eq2,y);
v
[y = --]
2
x
(%i8) eq3x : ( subst(soly, eq3),factor(%%) );
3
2 x (x - v)
(%o8)
- ------------ = 0
v
(%o7)
The factored form %o7 shows that, since x 6= 0, the solution must have x = v1/3 . We can then use this solution for x to
generate the solution for y and then for z.
(%i9) solx : x = v(1/3);
1/3
(%o9)
(%i10) soly : subst(solx, soly);
x = v
1/3
(%o10)
[y = v
]
(%i11) subst( [solx,soly[1] ], solz );
1/3
(%o11)
[z = v
]
We find that > 0 and that the second derivative of s(x, y) with respect to x is positive, as needed for the cubical
solution to define a minimum surface solution.
(%i12) delta : ( diff(s,x,2)*diff(s,y,2) - diff(s,x,1,y,1), expand(%%) );
2
16 v
(%o12)
----- - 2
3 3
x y
(%i13) delta : subst([x3=v,y3=v], delta );
(%o13)
14
(%i14) dsdx2 : diff(s,x,2);
4 v
(%o14)
--3
x
(%i15) dsdy2 : diff(s,y,2);
4 v
(%o15)
--3
y
6 DIFFERENTIAL CALCULUS
18
We see that one way we can get dsdx to be zero is to set sin() = 0, however this would mean the angle of bend was zero degrees,
which is not the solution of interest. Hence our first equation comes from setting the second factor of dsdx equal to zero.
(%i3) eq1 : dsdx/sin(th) = 0;
(%o3)
L + 2 cos(th) x - 4 x = 0
(%i4) solx : solve(eq1,x);
L
(%o4)
[x = - -------------]
2 cos(th) - 4
(%i5) dsdth : ( diff(s,th), factor(%%) );
2
2
(%o5)
x (cos(th) L - sin (th) x + cos (th) x - 2 cos(th) x)
6 DIFFERENTIAL CALCULUS
19
We see that we can get dsdth to be zero if we set x = 0, but this is not the physical situation we are examining. We
assume (of course) that x 6= 0, and arrive at our second equation of condition I by setting the second factor of dsdth
equal to zero.
(%i6) eq2 : dsdth/x = 0;
2
2
(%o6)
cos(th) L - sin (th) x + cos (th) x - 2 cos(th) x = 0
(%i7) eq2 : ( subst(solx,eq2), ratsimp(%%) );
2
2
(sin (th) + cos (th) - 2 cos(th)) L
(%o7)
----------------------------------- = 0
2 cos(th) - 4
The only way we can satisfy eq2 is to set the numerator of the left hand side equal to zero, and divide out the factor L
which is positive:
(%i8) eq2 : num(lhs(eq2) )/L = 0;
2
2
(%o8)
sin (th) + cos (th) - 2 cos(th) = 0
(%i9) eq2 : trigsimp(eq2);
(%o9)
1 - 2 cos(th) = 0
(%i10) solcos : solve( eq2, cos(th) );
1
(%o10)
[cos(th) = -]
2
(%i11) solx : subst(solcos, solx);
L
(%o11)
[x = -]
3
(%i12) solth : solve(solcos,th);
solve is using arc-trig functions to get a solution.
Some solutions will be lost.
%pi
(%o12)
[th = ---]
3
2 x
We can indicate explicitly that y depends on x for purposes of taking this derivative by replacing y by y(x).
(%i2) diff(x2 + y(x)2,x);
(%o2)
d
2 y(x) (-- (y(x))) + 2 x
dx
6 DIFFERENTIAL CALCULUS
20
Instead of using the functional notation to indicate dependency, we can use the depends function before taking the
derivative.
(%i3) depends(y,x);
(%o3)
(%i4) g : diff(x2 + y2, x);
(%o4)
[y(x)]
dy
2 y -- + 2 x
dx
(%i5) grind(g)$
2*y*diff(y,x,1)+2*x$
(%i6) gs1 : subst(diff(y,x) = x3, g );
3
(%o6)
2 x y + 2 x
In %i4 we defined g as the derivative (with respect to x) of the expression x2 + y2, after telling Maxima that the
symbol y is to be considered dependent on the value of x. Since Maxima, as yet, has no specific information about the
nature of the dependence of y on x, the output is expressed in terms of the noun form of diff, which Maximas pretty
print shows as dd yx . To see the internal form, we again use the grind function, which shows the explicit noun form
diff(y,x,1). This is useful to know if we want to later replace that unknown derivative with a known result, as we
do in input %i6.
However, Maxima doesnt do anything creative with the derivative substitution done in %i6, like working backwards to
what the explicit function of x the symbol y might stand for (different answers differ by a constant). The output %o6 still
contains the symbol y.
Two ways to later implement our knowledge of y(x) are shown in steps %i7 and %i8, which use the ev function. (In
Chapter 1 we discussed using ev for making substitutions, although the use of subst is more generally recommended
for that job.)
(%i7) ev(g,y=x4/4,diff);
(%o7)
7
x
-- + 2 x
2
(%i8) ev(g,y=x4/4,nouns);
(%o8)
(%i9) y;
(%o9)
(%i10) g;
(%o10)
7
x
-- + 2 x
2
y
dy
2 y -- + 2 x
dx
We see that Maxima does not bind the symbol y to anything when we call ev with an equation like y = x4/4, and
that the binding of g has not changed.
A list which reminds you of all dependencies in force is dependencies. The Maxima function diff is the only
core function which makes use of the dependencies list. The functions integrate and laplace do not use the
depends assignments; one must indicate the dependence explicitly by using functional notation.
6 DIFFERENTIAL CALCULUS
21
In the following, we first ask for the contents of the dependencies list and then ask Maxima to remove the above
dependency of y on x, using remove, then check the list contents again, and carry out the previous differentiation with
Maxima no longer assuming that y depends on x.
(%i11)
(%o11)
(%i12)
(%o12)
(%i13)
(%o13)
(%i14)
(%o14)
dependencies;
[y(x)]
remove(y, dependency);
done
dependencies;
[]
diff(x2 + y2,x);
2 x
On can also remove the properties associated with the symbol y by using kill (y), although this is more drastic than
using remove.
(%i15)
(%o15)
(%i16)
(%o16)
(%i17)
(%o17)
(%i18)
(%o18)
(%i19)
(%o19)
depends(y,x);
[y(x)]
dependencies;
[y(x)]
kill(y);
done
dependencies;
[]
diff(x2+y2,x);
2 x
There are many varieties of using the kill function. The way we are using it here corresponds to the syntax:
Function: kill (a_1, ..., a_n)
Removes all bindings (value, function, array, or rule) from the arguments a_1, ..., a_n. An argument a_k may
be a symbol or a single array element.
The list dependencies is one of the lists Maxima uses to hold information introduced during a work session. You can
use the command infolists to obtain a list of the names of all of the information lists in Maxima.
(%i1) infolists;
(%o2) [labels, values, functions, macros, arrays, myoptions, props, aliases,
rules, gradefs, dependencies, let_rule_packages, structures]
When you first start up Maxima, each of the above named lists is empty.
(%i2) functions;
(%o2)
[]
[y(x)]
d
-- (f(x, y))
dx
6 DIFFERENTIAL CALCULUS
22
We can make progress by assigning values to the partial derivative of f (x, y) with respect to the first argument x and
also to the partial derivative of f (x, y) with respect to the second argument y, using the gradef function. The assigned
values can be explicit mathematical expressions or symbols. We are going to adopt the symbol dfdx to stand for the
partial derivative
f (x, y)
dfdx =
,
x
y
where the y subscript means treat y as a constant when evaluating this derivative.
Likewise, we will use the symbol dfdy to stand for the partial derivative of f (x, y) with respect to y, holding x
constant:
f (x, y)
dfdy =
.
y
x
(%i3) gradef(f(x,y), dfdx, dfdy );
(%o3)
(%i4) g : diff( f(x,y), x );
(%o4)
f(x, y)
dy
dfdy -- + dfdx
dx
(%i5) grind(g)$
dfdy*diff(y,x,1)+dfdx$
(%i6) g1 : subst(diff(y,x) = dydx, g);
(%o6)
dfdy dydx + dfdx
We have adopted the symbol dydx for the rate of change of y as x varies, subject to the constraint that the numbers
(x, y) always satisfy the equation of the curve f (x, y) = 0, which implies that g1 = 0.
(%i7) solns : solve(g1=0, dydx);
(%o7)
dfdx
[dydx = - ----]
dfdy
We see that Maxima knows enough about the rules for differentiation to allow us to get to a famous calculus formula. If
x and y are constrained by the equation f (x, y) = 0, then the slope of the local tangent to the point (x, y) is
f (x,y)
x
y
dy
.
=
f (x,y)
dx
y
(6.8)
Of course, this formal expression has no meaning at a point where the denominator is zero.
In your calculus book you will find the derivation of the differentiation rule embodied in our output %o4 above:
d
f (x, y(x)) =
dx
f (x, y)
x
+
y
f (x, y)
y
d y(x)
x dx
(6.9)
Remember that Maxima knows only what the code writers put in; we normally assume that the correct laws of mathematics are encoded as an aid to calculation. If Maxima were not consistent with the differentiation rule Eq. (6.9), then a bug
would be present and would have to be removed.
The result Eq.(6.8) provides a way to find the slope (which we call m) at a general point (x, y).
This slope should be evaluated at the curve point (x0 , y0 ) of interest to get the tangent and normal in numerical
form. Recall our discussion in the first part of Section(6.3) where we derived the relation between the slopes of the tangent
and normal. If the numerical value of the slope is m0 , then the tangent (line) is the equation y = m0 (x x0 ) + y0 , and
the normal (line) is the equation y = (x x0 )/m0 + y0
6 DIFFERENTIAL CALCULUS
23
x
- -2
y
Maxima does not simplify r1 by cancelling the minus signs automatically, and we have resorted to dividing the negative
of the numerator by the negative of the denominator(!) to get the form of r2. Notice also that Maxima has chosen to
write sin(y2 x2 ) instead of sin(x2 y2 ).
Finally, find d y/d x given that 3 y4 + 4 x x2 sin(y) 4 = 0.
(%i5) dydx(3*y4 +4*x -x2*sin(y) - 4, x, y );
2 x sin(y) - 4
(%o5)
----------------3
2
12 y - x cos(y)
6 DIFFERENTIAL CALCULUS
24
We then choose a point of the circle, evaluate the slope at that point, and construct the tangent and normal at that point.
(%i4)
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
(%o8)
fpprintprec:8$
[x0,y0] : [0.5,0.866];
[0.5, 0.866]
m : subst([x=x0,y=y0],m );
- 0.577367
tangent : y = m*(x-x0) + y0;
y = 0.866 - 0.577367 (x - 0.5)
normal : y = -(x-x0)/m + y0;
y = 0.866 - 1.732 (0.5 - x)
We can then use qdraw to show the circle with both the tangent and normal.
(%i9) load(draw);
(%o9)
C:/PROGRA1/MAXIMA4.0/share/maxima/5.15.0/share/draw/draw.lisp
(%i10) load(qdraw);
qdraw(...), qdensity(...), syntax: type qdraw();
(%o10)
c:/work2/qdraw.mac
(%i11) ratprint:false$
(%i12) qdraw(key(bottom),ipgrid(15),
imp([ f = 0,tangent,normal],x,-2.8,2.8,y,-2,2 ),
pts([ [0.5,0.866]],ps(2) ) )$
The result is
2
1.5
1
0.5
0
-0.5
-1
1
2
3
-1.5
-2
-2
-1
6 DIFFERENTIAL CALCULUS
25
6.5.3 Example 2: Tangent and Normal of a Point of the Curve sin(2 x) cos(y) = 0.5
A curve is defined by f (x, y) = sin(2 x) cos(y) 0.5 = 0, with 0 x 2 and 0 y 2. Using Eq. (6.8) we
calculate the slope of the tangent to this curve at some point (x, y) and then specialize to the point (x = 1, y = y0 ) with
y0 to be found:
(%i13) f : sin(2*x)*cos(y) - 0.5$
(%i14) m : dydx(f,x,y);
2 cos(2 x) cos(y)
(%o14)
----------------sin(2 x) sin(y)
(%i15) s1 : solve(subst(x=1,f),y);
solve is using arc-trig functions to get a solution.
Some solutions will be lost.
1
(%o15)
[y = acos(--------)]
2 sin(2)
(%i16) fpprintprec:8$
(%i17) s1 : float(s1);
(%o17)
[y = 0.988582]
(%i18) m : subst([ x=1, s1[1] ], m);
1.3166767 cos(2)
(%o18)
---------------sin(2)
(%i19) m : float(m);
(%o19)
- 0.602587
(%i20) mnorm : -1/m;
(%o20)
1.6595113
(%i21) y0 : rhs( s1[1] );
(%o21)
0.988582
(%i22) qdraw( imp([f = 0, y - y0 = m*(x - 1),
y - y0 = mnorm*(x - 1) ],x,0,2,y,0,1.429),
pts( [ [1,y0] ], ps(2) ), ipgrid(15))$
1
2
3
1.2
1
0.8
0.6
0.4
0.2
0
0
0.5
1.5
Figure 10: Tangent and Normal to sin(2 x) cos(y) = 0.5 at point (1, 0.988)
6 DIFFERENTIAL CALCULUS
26
6.5.4 Example 3: Tangent and Normal of a Point on a Parametric Curve: x = sin(t), y = sin(2 t)
This example is the parametric curve example we plotted in Ch. 5. If we divide the differential of y by the differential of
x, the common factor of d t will cancel out and we will have an expression for the slope of the tangent to the curve at a
point determined by the value the parameter t, which in this example must be an angle expressed in radians (as usual in
calculus).
We then specialize to a point on the curve corresponding to x = 0.8, with 0 t /2, which we solve for:
(%i23) m : diff(sin(2*t))/diff(sin(t));
2 cos(2 t)
(%o23)
---------cos(t)
(%i24) x0 : 0.8;
(%o24)
0.8
(%i25) tsoln : solve(x0 = sin(t), t);
4
(%o25)
[t = asin(-)]
5
(%i26) tsoln : float(tsoln);
(%o26)
[t = 0.927295]
(%i27) t0 : rhs( tsoln[1] );
(%o27)
0.927295
(%i28) m : subst( t = t0, m);
(%o28)
- 0.933333
(%i29) mnorm : -1/m;
(%o29)
1.0714286
(%i30) y0 : sin(2*t0);
(%o30)
0.96
(%i31) qdraw( xr(0, 2.1), yr(0,1.5), ipgrid(15),nticks(200),
para(sin(t),sin(2*t),t,0,%pi/2, lc(brown) ),
ex([y0+m*(x-x0),y0+mnorm*(x-x0)],x,0,2.1 ),
pts( [ [0.8, 0.96]],ps(2) ) )$
1.4
1.2
1
0.8
0.6
0.4
0.2
0
0
0.5
1.5
Figure 11: Tangent and Normal to x = sin(t), y = sin(2 t) at point t = 0.927 radians
6 DIFFERENTIAL CALCULUS
27
6.5.5 Example 4: Tangent and Normal of a Point on a Polar Plot: x = r(t) cos(t), y = r(t) sin(t)
We use the polar plot example from ch. 5, in which we took r(t) = 10/t, and again t is in radians, and we consider
the interval 1 t and find the tangent and normal at the curve point corresponding to t = 2 radians. We find the
general slope of the tangent by again forming the ratio of the differential dy to the differential dx.
(%i32)
(%i33)
(%i34)
(%i35)
(%i36)
r : 10/t$
xx : r * cos(t)$
yy : r * sin(t)$
m : diff(yy)/diff(xx)$
m : ratsimp(m);
sin(t) - t cos(t)
----------------t sin(t) + cos(t)
(%o36)
(%i37)
(%o37)
(%i38)
(%o38)
(%i39)
(%o39)
(%i40)
(%o40)
(%i41)
1
2
t = 2 rad
-2
-6
-4
-2
10
6 DIFFERENTIAL CALCULUS
28
example(limit)$
limit(x*log(x),x,0,plus)
0
limit((x+1)(1/x),x,0)
%e
limit(%ex/x,x,inf)
inf
limit(sin(1/x),x,0)
ind
Most use of limit will use the first two ways to call limit. The direction argument is optional. The default values
of the option switches mentioned above are:
(%i6) [lhospitallim,tlimswitch,limsubst];
(%o6)
[4, true, false]
Thus the default Maxima behavior is to allow the use of a Taylor series expansion in finding the correct limit. (We will
discuss Taylor series expansions soon in this chapter.) The default is also to prevent substitutions on unknown (formal)
functions. The third (single argument) syntax is illustrated by
(%i7) limit(inf - 1);
(%o7)
inf
The expression presented to the limit function in input %i7 contains only known constants, so there are no unbound
(formal) parameters like x for limit to worry about.
Here is a use of limit which mimics the calculus definition of a derivative of a power of x.
(%i8) limit( ( (x+eps)3 - x3 )/eps, eps, 0 );
2
(%o8)
3 x
6 DIFFERENTIAL CALCULUS
29
What does Maxima do with a typical calculus definition of a derivative of a trigonometric function?
(%i10) limit((sin(x+eps)-sin(x))/eps, eps,0 );
Is sin(x) positive, negative, or zero?
p;
Is cos(x) positive, negative, or zero?
p;
(%o10)
cos(x)
We see above a typical Maxima query before producing an answer. Using p; instead of positive; is allowed. Likewise
one can use n; instead of negative;.
6.6.1 Discontinuous Functions
A simple example of a discontinuous function can be created using Maximas abs function.
abs(expr) returns either the absolute value expr, or (if expr is complex) the complex modulus of expr.
We first plot the function |x|/x.
(%i11) load(draw)$
(%i12) load(qdraw)$
(%i13) qdraw( yr(-2,2),lw(8),ex(abs(x)/x,x,-1,1 ) )$
1.5
1
0.5
0
-0.5
-1
-1.5
-2
-1
-0.5
0.5
6 DIFFERENTIAL CALCULUS
30
1
- 1
und
(%o17)
(%i18) g, x = 0.5;
(%o18)
0.0
(%i19) g, x = - 0.5;
(%o19)
0.0
(%i20) g,x=0;
Division by 0
-- an error. To debug this try debugmode(true);
(%i21) limit(g,x,0,plus);
(%o21)
0
(%i22) limit(g,x,0,minus);
(%o22)
0
(%i23) load(vcalc)$
(%i24) plotderiv(abs(x)/x,x,-2,2,-2,2,1)$
abs(x)
1
abs(x)
plist = [------, ------ - ------]
x
abs(x)
2
x
The derivative does not simplify to 0 since the derivative is undefined at x = 0. The plot of the step function and its
derivative, as returned by plotderiv is
2
1
2
1.5
1
0.5
0
-0.5
-1
-1.5
-2
-1
-0.5
0.5
6 DIFFERENTIAL CALCULUS
31
A homemade unit step function can now be defined by adding 1 to lift the function up to the value of 0 for x < 0 and
then dividing the result by 2 to get a unit step function.
(%i25) mystep : ( (1 + abs(x)/x)/2 , ratsimp(%%) );
abs(x) + x
(%o25)
---------2 x
1.5
0.5
-0.5
-1
-1
-0.5
0.5
Of course, defining the derivative to be 0 everywhere can be dangerous in some circumstances. You can use unit_step
in a plot using, say, qdraw(yr(-1,2),lw(5),ex(unit_step(x),x,-1,1) );. Here we use unit_step to
define a unit pulse function upulse(x,x0,w) which is a function of x which becomes equal to 1 when x = x0 and
has width w.
(%i32) upulse(x,x0,w) := unit_step(x-x0) - unit_step(x - (x0+w))$
6 DIFFERENTIAL CALCULUS
32
1.5
0.5
-0.5
-1
-3
-2
-1
The eps image reproduced here actually uses a finer line width than the Windows Gnuplot console window:
1
0.8
0.6
0.4
0.2
0
-0.2
-0.4
-0.6
-0.8
-1
0.001
0.002
0.003
0.004
0.005
0.006
0.007
0.008
0.009
0.01
6 DIFFERENTIAL CALCULUS
33
The Maxima limit function correctly returns ind for indefinite but bounded when asked to find the limit as
x 0+ .
(%i35) limit(sin(1/x),x,0,plus);
(%o35)
ind
An example of a function which is well behaved at x = 0 but whose derivative is indefinite but bounded is x2 sin(1/x),
which approaches the value 0 at x = 0.
(%i36) g : x2*sin(1/x)$
(%i37) limit(g,x,0);
(%o37)
(%i38) dgdx : diff(g,x);
0
1
1
2 sin(-) x - cos(-)
x
x
(%o38)
(%i39) limit(dgdx,x,0);
(%o39)
ind
In the first term of the derivative, x sin(1/x) is driven to 0 by the factor x, but the second term oscillates increasingly
rapidly between 1 as x 0. For a plot, we use the smallest line width and color blue for the derivative, and use a
thicker red curve for the original function x2 sin(1/x).
(%i40) qdraw( yr(-1.5,1.5),ex1(2*x*sin(1/x)-cos(1/x),x,-1,1,lw(1),lc(blue)),
ex1(x2*sin(1/x),x,-1,1,lc(red) ) )$
0.5
-0.5
-1
-1.5
-1
-0.5
0.5
6 DIFFERENTIAL CALCULUS
34
To expand an expression depending on two variables, say (x,y), there are two essentially different forms. The first form
is
taylor(expr, [x,y], [a,b],n )
which will expand in x about x = a and expand in the variable y about y = b, up through combined powers of order
n. If a = b, then the simpler syntax:
taylor(expr, [x,y], a, n )
will suffice.
6 DIFFERENTIAL CALCULUS
(%i8) t4 : taylor(sin(x+y),[x,y],0,3);
3
2
2
3
x + 3 y x + 3 y x + y
(%o8)/T/
y + x - ------------------------- + . . .
6
(%i9) (subst( [x=%pi/2, y=%pi/2], t4), ratsimp(%%) );
3
%pi - 6 %pi
(%o9)
- -----------6
(%i10) ( at( t4, [x=%pi/2,y=%pi/2]), ratsimp(%%) );
3
%pi - 6 %pi
(%o10)
- -----------6
Note the crucial difference between this last example and the next.
(%i11) t5 : taylor(sin(x+y),[x,0,3],[y,0,3] );
3
2
3
y
y
y
y
2
(%o11)/T/ y - -- + . . . + (1 - -- + . . .) x + (- - + -- + . . .) x
6
2
2
12
2
1
y
3
+ (- - + -- + . . .) x + . . .
6
12
(%i12) (subst([x=%pi/2,y=%pi/2],t5),ratsimp(%%) );
5
3
%pi - 32 %pi + 192 %pi
(%o12)
-----------------------192
35
6 DIFFERENTIAL CALCULUS
36
A common use of the Taylor series is to expand a function of x in the form f (x + dx), for dx small.
(%i17) taylor(f(x+dx),dx,0,3);
!
d
!
(%o17)/T/ f(x) + (--- (f(x + dx))!
ddx
!
!dx = 0
!
2
!
d
!
2
(---- (f(x + dx))!
) dx
2
!
ddx
!
!dx = 0
) dx + ----------------------------2
!
3
!
d
!
3
(---- (f(x + dx))!
) dx
3
!
ddx
!
!dx = 0
+ ----------------------------- + . . .
6
(%i18) taylor(cos(x+dx),dx,0,4);
2
3
4
cos(x) dx
sin(x) dx
cos(x) dx
(%o18)/T/ cos(x) - sin(x) dx - ---------- + ---------- + ---------- + . . .
2
6
24
Another frequent use of the Taylor series is the expansion of a function which contains a small parameter which we will
symbolize by e.
(%i19) g : log(a/e + sqrt(1+(a/e)2 ) );
2
a
a
log(- + sqrt(-- + 1))
e
2
e
(%o19)
(%i20) taylor(g,e,0,2);
(%o20)/T/
2
e
- log(e) + log(2 a) + . . . + ---- + . . .
2
4 a
More examples of Taylor and Laurent series expansions can be found in the Maxima manual.
6 DIFFERENTIAL CALCULUS
37
seen for inputs which end with a semi-colon, whereas there are no output numbers for inputs which end with the dollar
sign. Once you get a little practice reading the text form of the batch file and comparing that to the Maxima display of the
batched in file, you should have no problem understanding what is going on. The first lines of vcalcdem.mac are:
" vcalcdem.mac: sample calculations and derivations"$
" default coordinates are cartesian (x,y,z)"$
" gradient and laplacian of a scalar field "$
depends(f,[x,y,z]);
grad(f);
lap(f);
Here is what you will see in your Maxima session:
(%i1) load(vcalc);
vcalc.mac:
The default coordinates are cartesian (x,y,z), and by telling Maxima that the otherwise undefined symbol f is to be
treated as an explicit function of (x,y,z), we get symbolic output from grad(f) and lap(f) which respectively
produce the gradient and laplacian in the current coordinate system.
For each function used, a reminder is printed to your screen concerning the current coordinate system and the current
choice of independent variables.
Three dimensional vectors (the only kind allowed by this package) are represented by lists with three elements. In the
default cartesian coordinate system (x,y,z), the first slot is the x component of the vector, the second slot is the y
component, and the third slot is the z component.
Now that you have seen the difference between the file vcalcdem.mac and the Maxima response when using batch,
we will just show the latter for brevity. You can, of course, look at the file vcalcdem.mac with a text editor.
6 DIFFERENTIAL CALCULUS
38
Here the batch file displays the divergence and curl of a general 3-vector in a cartesian coordinate system.
(%i9)
(%i10)
(%o10)
(%i11)
(%o11)
(%i12)
cartesian
(%o12)
(%i13)
cartesian
[x, y, z]
daz
day dax
daz day
dax
[--- - ---, --- - ---, --- - ---]
dy
dz
dz
dx
dx
dy
(%o13)
[x,
[x,
[x,
[x,
and an example of finding the Laplacian of a vector field (rather than a scalar field) with an explicit example:
(%i17)
(%i18)
(%o18)
(%i19)
cartesian
[x, y, z]
3
(%o19)
[6 x y, 6 x y z, 2 y z
2
+ 6 x
y z]
and an example of the use of the vector cross product which is included with this package:
(%i20)
(%i21)
(%o21)
(%i22)
(%o22)
We next change the current coordinate system to cylindrical with a choice of the symbols rho, phi, and z as the
independent variables. We again start with some general expressions
(%i23)
(%i24)
(%o24)
(%i25)
(%i26)
(%o26)
6 DIFFERENTIAL CALCULUS
(%i27)
cylindrical
grad(g)
[rho, phi, z]
dg
---dg
dphi dg
[----, ----, --]
drho rho
dz
lap(g)
(%o27)
(%i28)
cylindrical
(%o28)
(%i29)
(%i30)
(%o30)
(%i31)
(%o31)
(%i32)
cylindrical
(%o32)
(%i33)
cylindrical
(%o33)
39
[rho, phi, z]
2
d g
dg
-------2
2
2
drho
dphi
d g
d g
---- + ----- + --- + ----rho
2
2
2
rho
dz
drho
divergence and curl of a vector field
bvec : [brh, bp, bz]
[brh, bp, bz]
depends(bvec, [rho, phi, z])
[brh(rho, phi, z), bp(rho, phi, z), bz(rho, phi, z)]
div(bvec)
[rho, phi, z]
dbp
---brh
dphi
dbz
dbrh
--- + ---- + --- + ---rho
rho
dz
drho
curl(bvec)
[rho, phi, z]
dbz
dbrh
------dphi
dbp dbrh
dbz
dphi
bp
dbp
[---- - ---, ---- - ----, - ---- + --- + ----]
rho
dz
dz
drho
rho
rho
drho
Instead of using setcoord to change the current coordinate system, we can insert an extra argument in the vector
calculus function we are using. Here is an example of not changing the coordinate system, but telling Maxima to use r
instead of rho with the currently operative cylindrical coordinates.
(%i34)
6 DIFFERENTIAL CALCULUS
40
(%i40)
coordinate system remains spherical unless explicitly changed
(%i41)
cvec : [0, 0, r sin(theta)]
(%i42)
div(cvec)
spherical polar [r, theta, phi]
(%o42)
0
(%i43)
example of div(vec) = 0 everywhere except r = 0
1
(%i44)
div([--, 0, 0])
2
r
spherical polar [r, theta, phi]
(%o44)
0
The best way to get familiar with vcalc.mac is just to play with it. Some syntax descriptions are built into the package.
6 DIFFERENTIAL CALCULUS
41
[g(u, v, w)]
If, at this point, we ask for the derivative of g with respect to x, we get zero, since Maxima has no information yet about
dependence of u, v, and w on x.
(%i2) diff(g,x);
(%o2)
which now allows Maxima to demonstrate its knowledge of the calculus chain rule, which Maxima writes as:
(%i4) diff(g,x);
(%o4)
dg dw
dg dv
dg du
-- -- + -- -- + -- -dw dx
dv dx
du dx
Note how Maxima writes the chain rule in this example, which would be written (using partial derivative notation) in a
calculus text as
g(u, v, w) u(x, y, z) g(u, v, w) v(x, y, z) g(u, v, w) w(x, y, z)
g(u, v, w)
=
+
+
x
u
x
v
x
w
x
(6.10)
In addition to using a depends statement to tell Maxima about the (x, y, z) dependence of (u, v, w) , we can use the
gradef function to replace derivatives with chosen substitutes.
(%i5) (gradef(u,x,dudx),gradef(u,y,dudy),gradef(u,z,dudz),
gradef(v,x,dvdx),gradef(v,y,dvdy),gradef(v,z,dvdz),
gradef(w,x,dwdx),gradef(w,y,dwdy),gradef(w,z,dwdz) )$
dg
dg
dg
dwdx -- + dvdx -- + dudx -dw
dv
du
(%i7) grind(%)$
dwdx*diff(g,w,1)+dvdx*diff(g,v,1)+dudx*diff(g,u,1)$
This is the method we will use in both this section on cylindrical coordinates and in the next section on spherical polar
coordinates.
In the following sections we discuss successive parts of a batch file cylinder.mac, available with this chapter on
the authors webpage. This file is designed to be introduced into Maxima with the input: batch(cylinder) (if
cylinder.mac is in your work directory, say, and you have set up your file search paths as suggested in Ch. 1), or
batch("c:/work5/cylinder.mac") if you need to supply the complete path. We have given some orientation
concerning batch files in the previous section.
6 DIFFERENTIAL CALCULUS
42
Relating (x, y) to (, )
In cylinder.mac we use rh to represent and p to represent the angle expressed in radians. The ranges of the
independent variables are 0 < < , 0 2 , and z +.
Here is the beginning of the batch file cylinder.mac. First is defined c3rule as a list of replacement rules in the
form of equations which can be used later by the subst function as described by c3sub. rhxy stands for an expression
which produces given (x, y). To get automatic simplification of rh/abs(rh) we use the assume function.
" ------------ cylinder.mac
----------------------------"$
" cylindrical coordinates (rho, phi, z ) = (rh, p, z) "$
" replacement rules x,y,z to rh, p, z
"$
Now that you have seen what Maxima does with a file introduced into Maxima via batch("cylinder.mac"),
we will stop displaying the contents of cylinder.mac but just show you Maximas response. You can look at
cylinder.mac with a text editor to compare input with output.
We next tell Maxima how to work with the cylindrical coordinates and their derivatives: We let the symbol drhdx, for
example, hold (for later use) / x.
(%i9)
(%i10)
(%o10)
(%i11)
(%o11)
(%i12)
(%o12)
(%i13)
(%o13)
6 DIFFERENTIAL CALCULUS
43
(6.11)
(6.12)
(6.13)
(6.14)
The batch file has not used any depends or gradef assignments so far. What the batch file did could have been done
interactively, starting with the derivative of with respect to x, say, as follows
(%i1) rhxy : sqrt(x2 + y2);
2
(%o1)
(%i2) diff(rhxy,x);
sqrt(y
2
+ x )
x
------------2
2
sqrt(y + x )
subst([x=rh*cos(p),y=rh*sin(p)],%);
cos(p) rh
------------------------------2
2
2
2
sqrt(sin (p) rh + cos (p) rh )
trigsimp(%);
cos(p) rh
--------abs(rh)
assume(rh > 0)$
ev (%o4);
cos(p)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%i6)
(%o6)
and if we had used assume(rh > 0) earlier, we would not have had to include the ev step later, as you can verify by
restarting Maxima or using kill(all) to redo the calculation.
Returning to the batch file, the necessary variable dependencies and the desired derivative replacements are assigned:
(%i14)
(%i15)
(%i16)
(%i17)
6.9.2 Laplacian
2 f (, , z)
(6.15)
The batch file now calculates the Laplacian of a scalar function f when the function depends explicitly on the cylindrical
coordinates (, , z) and hence depends implicitly on (x, y) since and each depend on (x, y). This latter dependence
has already been introduced via depends, together with an automatic derivative substitution via gradef.
6 DIFFERENTIAL CALCULUS
44
The batch file tells Maxima to treat f as an explicit function of rh, p, and z via depends(f,[rh,p,z]). At that
point, if the batch file had asked for the first derivative of f with respect to x, the response would be
(%i98) diff (f,x);
(%o98)
df
-- sin(p)
df
dp
--- cos(p) - --------drh
rh
The cartesian form of the Laplacian of f can thus be expressed in terms of the fundamental set of derivatives / x,
etc., which have already been established above. The next section of cylinder.mac then produces the response:
(%i18)
-----------------------------------------------(%i19)
Laplacian of a scalar function f
(%i20)
-----------------------------------------------(%i21)
tell Maxima to treat scalar function f as an
(%i22)
explicit function of (rh,p,z)
(%i23)
depends(f, [rh, p, z])
(%o23)
[f(rh, p, z)]
(%i24)
calculate the Laplacian of the scalar function f(rh,p,z)
(%i25)
using the cartesian definition
(%i26) (diff(f, z, 2) + diff(f, y, 2) + diff(f, x, 2), trigsimp(%%),
multthru(%%))
2
d f
df
----2
2
2
drh
dp
d f
d f
(%o26)
--- + --- + --- + ---rh
2
2
2
rh
dz
drh
(%i27)
grind(%)
diff(f,rh,1)/rh+diff(f,p,2)/rh2+diff(f,z,2)+diff(f,rh,2)$
1f
2f
+
1 2f
2f
+
2 2
z2
2f
f
1f
1
+
=
(6.16)
(6.17)
6 DIFFERENTIAL CALCULUS
45
(%i1) cylaplacian(expr,rho,phi,z) :=
(diff(expr,rho)/rho + diff(expr,phi,2)/rho2 +
diff(expr,rho,2) + diff(expr,z,2))$
We can show that the combinations n cos(n ) and n sin(n ) are each solutions of Laplaces equation
2 u = 0.
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
( cylaplacian(rhn*cos(n*p),rh,p,z), factor(%%) );
0
( cylaplacian(rhn*sin(n*p),rh,p,z), factor(%%) );
0
( cylaplacian(rh(-n)*cos(n*p),rh,p,z), factor(%%) );
0
( cylaplacian(rh(-n)*sin(n*p),rh,p,z), factor(%%) );
0
Here is another example of the use of this Maxima function. The expression u = (2/3) ( 1/) sin() is proposed
as the solution to a problem defined by: (partial differential equation: pde) 2 u = 0 for 1 2, and (boundary
conditions: bc) u(1, ) = 0, and u(2, ) = sin(). Here we use Maxima to check the three required solution properties.
(%i7) u : 2*(rh - 1/rh)*sin(p)/3$
(%i8) (cylaplacian(u,rh,p,z), ratsimp(%%) );
(%o8)
0
(%i9) [subst(rh=1,u),subst(rh=2,u) ];
(%o9)
[0, sin(p)]
6.9.3 Gradient
f (, , z)
There are several ways one can work with vector calculus problems. One method (not used here) is to use symbols for
a set of orthogonal unit vectors, and assume a set of properties for these unit vectors without connecting the set to any
specific list basis representation. One can then construct the dot product, the cross product and the derivative operations
in terms of the coefficients of these symbolic unit vectors (using ratcoeff, for example).
Alternatively (and used here), one can define 3-vectors in terms of three element lists, in which the first element of the list
contains the x axis component of the vector, the second element of the list contains the y axis component, and the third
element contains the z component.
This second method is less abstract and closer to the beginning students experience of vectors, and provides a straightforward path which can be used with any orthonormal coordinate system.
The unit vector along the x axis (
x) is represented by xu = [1,0,0] (for x - unit vector), the unit vector along the
y axis (
y) is represented by yu = [0,1,0], and the unit vector along the z axis (
z) is represented by zu = [0,0,1].
Lets return to the batch file cylinder.mac, where we define lcross(u,v) to calculate the vector cross product
u v when we are using three element lists to represent vectors.
Note that our orthonormality checks use the built-in dot product of lists provided by the period . (which is also used for noncommutative matrix multiplication). The dot product of two vectors represented by Maxima lists is obtained by placing a period
between the lists. We have checked that the cartesian vectors defined are unit vectors (the dot product yields unity) and are also
mutually orthogonal (ie., at right angles to each other) which is equivalent to the dot product of a pair of different unit vectors being
zero.
6 DIFFERENTIAL CALCULUS
46
This section of cylinder.mac begins with the code for lcross which looks like:
lcross(u,v) := (
( u[2]*v[3] - u[3]*v[2] )*xu +
( u[3]*v[1] - u[1]*v[3] )*yu +
( u[1]*v[2] - u[2]*v[1] )*zu )$
Note, in the batch file output, using display2d:true (the default), how the list element numbers are displayed as
subscripts.
(%i28)
-------------------------------------------(%i29)
Unit Vectors
(%i30)
-------------------------------------------(%i31)
cross product rule when using lists for vectors
(%i32) lcross(u, v) := (u v - u v ) zu + (u v - u v ) yu
1 2
2 1
3 1
1 3
+ (u
v
2
(%i33)
(%i34)
(%o34)
(%i35)
(%i36)
(%i37)
(%i38)
(%i39)
(%i40)
(%o40)
(%i41)
(%i42)
(%o42)
(%i43)
(%o43)
(%i44)
(%o44)
(%i45)
(%o45)
(%i46)
(%i47)
(%o47)
(%i48)
(%o48)
- u
3
v ) xu
2
=
x sin + y
cos
(6.19)
6 DIFFERENTIAL CALCULUS
47
(%i49)
cylindrical coordinate unit vectors rho-hat, phi-hat
(%i50)
rhu : sin(p) yu + cos(p) xu
(%o50)
[cos(p), sin(p), 0]
(%i51)
pu : cos(p) yu - sin(p) xu
(%o51)
[- sin(p), cos(p), 0]
(%i52)
orthonormality checks on unit vectors
(%i53) ([rhu . rhu, pu . pu, zu . zu, rhu . pu, rhu . zu, pu . zu],
trigsimp(%%))
(%o53)
[1, 1, 1, 0, 0, 0]
(%i54)
low tech check of cross products
(%i55)
(lcross(rhu, pu), trigsimp(%%)) - zu
(%o55)
[0, 0, 0]
(%i56)
(lcross(pu, zu), trigsimp(%%)) - rhu
(%o56)
[0, 0, 0]
(%i57)
(lcross(zu, rhu), trigsimp(%%)) - pu
(%o57)
[0, 0, 0]
(%i58)
[lcross(rhu, rhu), lcross(pu, pu)]
(%o58)
[[0, 0, 0], [0, 0, 0]]
(%i59)
high tech checks of cross products
(%i60) (map(apcr, [[rhu, pu], [pu, zu], [zu, rhu]]), trigsimp(%%))
- [zu, rhu, pu]
(%o60)
[[0, 0, 0], [0, 0, 0], [0, 0, 0]]
(%i61)
map(apcr, [[rhu, rhu], [pu, pu]])
(%o61)
[[0, 0, 0], [0, 0, 0]]
f
f
f
+y
+
z
x
y
z
(6.20)
For a scalar function f which depends explicitly on (, , z) and hence implicitly on (x, y), we can use the relations already established in cylinder.mac to convert the cartesian expression of the gradient of f (called here fgradient)
into an expression in terms of derivatives with respect to (, , z).
Returning to the output of cylinder.mac:
(%i62)
(%i63)
(%i64)
(%i65)
(%i66)
(6.21)
(6.22)
6 DIFFERENTIAL CALCULUS
(%i69)
(%o69)
(%i70)
(%o70)
48
f
1 f
f
+
+
z
.
(6.23)
B(, , z)
In cartesian coordinates the divergence of a three dimensional vector field B(x, y, z) can be calculated with the equation
B(x, y, z) =
Bx By
Bz
+
+
x
y
z
(6.24)
Consider a vector field B(, , z) which is an explicit function of the cylindrical coordinates , , z) and hence an implicit function of (x, y). We will use the symbol bvec to represent B(, , z), and use the symbols bx, by, and bz to
represent the x, y, and z components of B(, , z).
The component (the component in the direction of increasing with constant and constant z) of B(, , z) at the
point (, , z) is given by
B (, , z) = B(, , z).
(6.25)
We use the symbol brh for B (, , z) . The component of B(, , z) at the point (, , z) in the direction of increasing
(with constant and constant z) is given by the equation
B (, , z) =
B(, , z).
We use the symbol bp for B (, , z). Returning to the output of cylinder.mac batch file:
(%i71)
----------------------------------------------(%i72)
Divergence of a Vector bvec
(%i73)
----------------------------------------------(%i74)
bvec : bz zu + by yu + bx xu
(%o74)
[bx, by, bz]
(%i75)
two equations which relate cylindrical components
(%i76)
of bvec to the cartesian components
(%i77)
eq1 : brh = rhu . bvec
(%o77)
brh = by sin(p) + bx cos(p)
(%i78)
eq2 : bp = pu . bvec
(%o78)
bp = by cos(p) - bx sin(p)
(%i79)
invert these equations
(%i80)
sol : (linsolve([eq1, eq2], [bx, by]), trigsimp(%%))
(%o80)
[bx = brh cos(p) - bp sin(p), by = brh sin(p) + bp cos(p)]
(%i81)
[bx, by] : map(rhs, sol)
(%i82)
tell Maxima to treat cylindrical components as
(%i83)
explicit functions of (rh,p,z)
(%i84)
depends([brh, bp, bz], [rh, p, z])
(%o84)
[brh(rh, p, z), bp(rh, p, z), bz(rh, p, z)]
(%i85)
calculate the divergence of bvec
(%i86) bdivergence : (diff(bz, z) + diff(by, y) + diff(bx, x), trigsimp(%%),
multthru(%%))
dbp
--brh
dp
dbz
dbrh
(%o86)
--- + --- + --- + ---rh
rh
dz
drh
(6.26)
6 DIFFERENTIAL CALCULUS
49
6.9.5 Curl
1
1
Bz
( B ) +
B +
,
z
(6.27)
B
1
( B ) =
+
B
(6.28)
B(, , z)
In cartesian coordinates the curl of a three dimensional vector field B(x, y, z) can be calculated with the equation
By
By
Bz
Bx Bz
Bx
B(x, y, z) = x
+y
+
z
(6.29)
y
z
z
x
x
y
Remember that we have already bound the symbols bx and by to linear combinations of brh and bp, and have told
Maxima (using depends) to treat brh and bp as explicit functions of (rh,p,z). Hence our assignment of the symbol
bcurl in cylinder.mac will result in Maxima using the calculus chain rule. We can then extract the cylindrical
components of B by taking the dot product of the cylindrical unit vectors with B, just as we did to get the cylindrical
components of f .
Returning to the output of cylinder.mac:
(%i87)
-------------------------------------------------------(%i88)
Cylindrical Components of Curl(bvec)
(%i89)
-------------------------------------------------------(%i90)
cartesian definition of curl(vec)
(%i91) bcurl : (diff(by, x) - diff(bx, y)) zu + (diff(bx, z) - diff(bz, x)) yu
+ (diff(bz, y) - diff(by, z)) xu
(%i92)
find cylindrical components of curl(bvec)
(%i93)
bcurl_rh : (rhu . bcurl, trigsimp(%%), multthru(%%))
dbz
--dp
dbp
(%o93)
--- - --rh
dz
(%i94)
bcurl_p : (pu . bcurl, trigsimp(%%), multthru(%%))
dbrh
dbz
(%o94)
---- - --dz
drh
(%i95)
bcurl_z : (zu . bcurl, trigsimp(%%), multthru(%%))
dbrh
---dp
bp
dbp
(%o95)
- ---- + -- + --rh
rh
drh
(%i96)
-------------------------------------------------------
B(, , z) =
in which we have used
B
1 Bz
B Bz
+
z
B B
1
+
=
( B ).
1
1 B
( B )
(6.30)
(6.31)
6 DIFFERENTIAL CALCULUS
50
6 DIFFERENTIAL CALCULUS
(%i16)
(%o16)
(%i17)
(%o17)
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%i23)
(%i24)
51
Hence the form of the Laplacian of a scalar field in spherical polar coordinates:
f
1
2f
1
2 f
2
r
+ 2
sin
+ 2
f (r, , ) = 2
r r
r
r sin
r sin2 2
in which we have used the identities
and
2 f
1
2f
+
= 2
2
r
r r
r r
2 f
r
r
2f
cos f
1
+
=
2
sin
sin
f
sin
We need to avoid r = 0 and sin = 0. The latter condition means avoiding = 0 and = .
(6.32)
(6.33)
(6.34)
6 DIFFERENTIAL CALCULUS
52
=
x sin + y
cos
(6.35)
We can express
r and in terms of the cylindrical and
z (from the figure above):
and
r=
z cos + sin
(6.36)
=
z sin + cos .
(6.37)
r=x
sin cos + y
sin sin +
z cos
(6.38)
= x
cos cos + y
cos sin
z sin
(6.39)
Hence we have
and
Maxima has already been told to treat f as an explicit function of (r,t,p) which we are using for (r, , ). The vector
components of f are isolated by using the dot product of the unit vectors with f . For example,
(f )r =
r f
(%i35)
(%i36)
(%i37)
(%i38)
(%i39)
(%i40)
(%i41)
(%o41)
(%i42)
(%o42)
(%i43)
(%o43)
-------------------------------------------Unit Vectors
-------------------------------------------cartesian unit vectors
(xu : [1, 0, 0], yu : [0, 1, 0], zu : [0, 0, 1])
spherical polar coordinate unit vectors
ru : cos(t) zu + sin(t) sin(p) yu + sin(t) cos(p) xu
[cos(p) sin(t), sin(p) sin(t), cos(t)]
tu : - sin(t) zu + cos(t) sin(p) yu + cos(t) cos(p) xu
[cos(p) cos(t), sin(p) cos(t), - sin(t)]
pu : cos(p) yu - sin(p) xu
[- sin(p), cos(p), 0]
(6.40)
6 DIFFERENTIAL CALCULUS
(%i44)
(%i45)
(%i46)
(%i47)
(%i48)
(%i49)
(%i50)
(%o50)
(%i51)
(%o51)
(%i52)
(%o52)
53
1 f
1
f
f
+
+
r
r
r sin
(6.41)
6 DIFFERENTIAL CALCULUS
54
(%i68)
divergence of bvec
(%i69) bdivergence : (diff(bz, z) + diff(by, y) + diff(bx, x), trigsimp(%%),
scanmap(multthru, %%))
dbp
dbt
----bt cos(t)
dp
dt
2 br
dbr
(%o69)
--------- + -------- + --- + ---- + --r sin(t)
r sin(t)
r
r
dr
Hence we have the spherical polar coordinate version of the divergence of a vector field:
1 2
1
1 B
B(r, , ) = 2
r Br +
(sin B ) +
r r
r sin
r sin
using the identities
2
Br
1 2
Br +
= 2
r Br
r
r
r r
and
cos
B
1
B +
=
(sin B )
sin
sin
(6.43)
(6.44)
(6.45)
which produces the spherical polar coordinate version of the curl of a vector field:
B
( B)r =
(sin B )
r sin
1
1 Br
( B) =
(r B )
r sin
r
1
Br
( B) =
(r B )
r r
in which we have used Eq.(6.45) with B replaced by B and also Eq.(6.31) with replaced by r.
(6.46)
(6.47)
(6.48)
7.2 Integration Examples and also defint, ldefint, beta, gamma, erf, and logabs
Example 1
Our first example is the indefinite integral
sin3 x dx:
Notice that the indefinite integral returned by integrate does not include the arbitrary constant of integration
which can always be added.
If the returned integral is correct (up to an arbitrary constant), then the first derivative of the returned indefinite
integral should be the original integrand, although we may have to simplify the result manually (as we had to
do above).
Example 2
Our second example is another indefinite integral,
Example 3
The definite integral can be related to the area under a curve and is the more accessible concept, while the
integral is simply a function whose first derivative is the original integrand.
Here is a definite integral,
R
0
cos2 x ex dx:
(%o5)
%pi
3 %e
3
------- - 5
5
Instead of using integrate for a definite integral, you can try ldefint (think Limit definite integral), which may
provide an alternative form of the answer (if successful).
Here is an example of use of ldefint, as well as the direct use of defint (which bypasses integrate ):
(%i6) ldefint (cos(x)2 * exp(x), x, 0, %pi);
%pi
3 %e
3
(%o6)
------- - 5
5
(%i7) defint (cos(x)2 * exp(x), x, 0, %pi);
%pi
3 %e
3
(%o7)
------- - 5
5
Example 4
Here is an example of a definite integral over an infinite range,
x2 ex dx:
To check this integral, we first ask for the indefinite integral and then check it by differentiation.
(%i9) i1 : integrate(x2*exp(-x2),x );
2
- x
(%o9)
sqrt(%pi) erf(x)
x %e
---------------- - -------4
2
(%i10) diff(i1,x);
2
2
(%o10)
- x
%e
2
Thus the indefinite integral is correct. The second term, heavily damped by the factor ex at , does not
contribute to the definite integral. The first term is proportional to the (Gauss) error function, erf (x), in which
x is real. For (in general) complex w = u + i v,
Z w
2
2
ez dz
(7.1)
Erf (w) =
0
in which we can integrate over any path connecting 0 and w in the complex z = x + i y plane, since the
integrand is an entire function of z (no singularities in the finite z plane.
5
erf(x)
1.5
1
0.5
0
-0.5
-1
-1.5
-2
-4
-2
R
0
xa (x + 1)5/2 dx.
(%i1) (assume(a>1),facts());
(%o1)
[a > 1]
(%i2) integrate (xa/(x+1)(5/2), x, 0, inf );
2 a + 2
Is ------- an integer?
5
no;
Is 2 a - 3
neg;
(%o2)
3
beta(- - a, a + 1)
2
The combination of assume(a > 1) and 2 a 3 < 0 means that we are assuming 1 < a < 3/2.
These assumptions about a imply that 4/5 < (2 a + 2)/5 < 1. To be consistent, we must hence answer no to
the first question.
Lets tell Maxima to forget about the assume assignment and see what the difference is.
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
Is a
( forget(a>1), facts() );
[]
is( a>1 );
unknown
integrate (xa/(x+1)(5/2), x, 0, inf );
+ 1 positive, negative, or zero?
pos;
Is a an integer?
no;
7
Is ------- an integer?
2 a + 4
no;
Is 2 a - 3
neg;
3
beta(- - a, a + 1)
2
(%o5)
(%i6) [is( a>1 ), facts() ];
(%o6)
[unknown, []]
Thus we see that omitting the initial assume(a>1) statement causes integrate to ask four questions instead of two. We
also see that answering questions posed by the integrate dialogue script does not result in population of the facts list.
The Maxima beta function has the manual entry:
Function: beta (a, b)
The beta function is defined as gamma(a) gamma(b)/gamma(a+b) (A&S 6.2.1).
In the usual mathematics notation, the beta function can be defined in terms of the gamma function as
B(r, s) =
(r) (s)
(r + s)
(7.2)
z - 1
- t
%e
dt
The gamma function can be defined for complex z and Re(z) > 0 by the integral along the real t axis
Z
(z) =
tz1 et d t
(7.3)
and for Im(z) = 0 and Re(z) = n and n an integer greater than zero we have
(n + 1) = n !
(7.4)
How can we check the definite integral Maxima has offered? If we ask the integrate function for the indefinite integral,
we get the noun form, a signal of failure:
(%i7) integrate(xa/(x+1)(5/2), x );
/
a
[
x
(%o7)
I ---------- dx
]
5/2
/ (x + 1)
(%i8) grind(%)$
integrate(xa/(x+1)(5/2),x)$
Just for fun, lets include the risch flag and see what we get:
(%i9) integrate(xa/(x+1)(5/2), x ), risch;
/
a log(x)
[
%e
(%o9)
I -------------------------- dx
]
2
/ sqrt(x + 1) (x + 2 x + 1)
We again are presented with a noun form, but the integrand has been written in a different form, in which the identity
xA = eA ln(x)
has been used.
We can at least make a spot check for a value of the parameter a in the middle of the assumed range (1, 3/2), namely for
a = 5/4.
(%i10) float(beta(1/4,9/4));
(%o10)
3.090124462168955
(%i11) quad_qagi(x(5/4)/(x+1)(5/2),x, 0, inf);
(%o11)
[3.090124462010259, 8.6105700347616221E-10, 435, 0]
We have used the quadrature routine, quad_qagi (see Ch. 8) for a numerial estimate of this integral. The first element
of the returned list is the numerical answer, which agrees with the analytic answer.
(7.6)
(7.7)
Here we assign the derivative knowledge using gradef (as discussed in Ch. 6):
(%i1) gradef(q(u),sin(u2) )$
(%i2) integrand : sin(r(x)2)* diff(r(x),x ) /q( r(x) ) ;
d
2
(-- (r(x))) sin(r (x))
dx
(%o2)
---------------------q(r(x))
(%i3) integrate(integrand,x);
(%o3)
log(q(r(x)))
(%i4) diff(%,x);
d
2
(-- (r(x))) sin(r (x))
dx
(%o4)
---------------------q(r(x))
Note that integrate pays no attention to depend assignments, so the briefer type of notation which depend
allows with differentiation cannot be used with integrate:
(%i5) depends(r,x,q,r);
(%o5)
[r(x), q(r)]
(%i6) integrand : sin(r2)* diff(r,x) / q;
dr
2
-- sin(r )
dx
(%o6)
---------q
(%i7) integrate(integrand,x);
/
2 [ dr
sin(r ) I -- dx
] dx
/
(%o7)
--------------q
which is fatally flawed, since Maxima pulled both sin(r(x)2 ) and 1/q(r(x)) outside the integral.
Of course, the above depends assignment will still allow Maxima to rewrite the derivative of q with respect to
x using the chain rule:
(%i8) diff(q,x);
(%o8)
dq dr
-- -dr dx
We can obviously find the lowest common denominator and write this as the ratio of two polynomials, using
either rat or ratsimp.
(%i2) e11 : ratsimp(e1);
(%o2)
4
2
x + 3 x + 2
------------2
x - 3 x
Because the polynomial in the numerator is of higher degree than the polynomial in the denominator, this is
called an improper rational fraction. Any improper rational fraction can be reduced by division to a mixed
form, consisting of a sum of some polynomial and a sum of proper fractions. We can recover the partial
fraction representation in terms of proper rational fractions (numerator degree less than denominator degree)
by using partfrac(expr, var).
(%i3) e12 : partfrac(e11,x);
2
2
110
(%o3)
x + 3 x - --- + --------- + 12
3 x
3 (x - 3)
With this function of x expressed in partial fraction form, you are able to write down the indefinite integral
immediately (ie., by inspection, without using Maxima). But, of course, we want to practice using Maxima!
(%i4) integrate(e11,x);
3
2
2 log(x)
110 log(x - 3)
2 x + 9 x + 72 x
(%o4)
- -------- + -------------- + -----------------3
3
6
(%i5) integrate(e12,x);
3
2
2 log(x)
110 log(x - 3)
x
3 x
(%o5)
- -------- + -------------- + -- + ---- + 12 x
3
3
3
2
Maxima has to do less work if you have already provided the partial fraction form as the integrand; otherwise,
Maxima internally seeks a partial fraction form in order to do the integral.
10
Example 8
The next example shows that integrate can sometimes split the integrand into at least one piece which can be
integrated, and leaves the remainder as a formal expression (using the noun form of integrate). This may be
possible if the denominator of the integrand is a polynomial which Maxima can factor.
(%i6) e2: 1/(x4 - 4*x3 + 2*x2 - 7*x - 4);
1
(%o6)
-------------------------4
3
2
x - 4 x + 2 x - 7 x - 4
(%i7) integrate(e2,x);
/ 2
[ x + 4 x + 18
I ------------- dx
] 3
log(x - 4)
/ x + 2 x + 1
(%o7)
---------- - -----------------73
73
(%i8) grind(%)$
log(x-4)/73-(integrate((x2+4*x+18)/(x3+2*x+1),x))/73$
(%i9) factor(e2);
1
(%o9)
---------------------3
(x - 4) (x + 2 x + 1)
(%i10) partfrac(e2,x);
2
1
x + 4 x + 18
(%o10)
---------- - ----------------73 (x - 4)
3
73 (x + 2 x + 1)
We have first seen what Maxima can do with this integrand, using the grind function to clarify the resulting
expression, and then we have used factor and partfrac to see how the split-up arises. Despite a theorem
that the integral of every rational function can be expressed in terms of algebraic, logarithmic and inverse
trigonometric expressions, Maxima declines to return a symbolic expression for the second, formal, piece of
this integral (which is good because the exact symbolic answer is an extremely long expression).
Example 9: The logabs Parameter and log
There is a global parameter logabs whose default value is false and which affects what is returned with an
indefinite integral containing logs.
(%i11) logabs;
(%o11)
(%i12) integrate(1/x,x);
(%o12)
(%i13) diff(%,x);
(%o13)
false
log(x)
1
x
(%i14) logabs:true$
11
(%i15) integrate(1/x,x);
(%o15)
(%i16) diff(%,x);
log(abs(x))
1
x
(%o16)
(%i17) log(-1);
(%o17)
(%i18) float(%);
(%o18)
log(- 1)
3.141592653589793 %i
When we override the default and set logabs to true, the argument of the log function is wrapped with abs.
According to the manual
When doing indefinite integration where logs are generated, e.g. integrate(1/x,x), the answer is
given in terms of log(abs(...)) if logabs is true, but in terms of log(...) if logabs is false. For definite
integration, the logabs:true setting is used, because here evaluation of the indefinite integral at
the endpoints is often needed.
This produces
2
1.5
0.5
-0.5
-1
0
0.5
1.5
2.5
3.5
12
We next define a function which is (x 1) for 1 x < 2 and is (6 2 x) for 2 x 3 and is 0 otherwise.
(%i5) g(x):= if x >= 1 and x < 2 then (x-1)
elseif x >= 2 and x <= 3 then (6 - 2*x) else 0$
(%i6) map(g,[1/2,1,3/2,2,5/2,3,7/2]);
1
(%o6)
[0, 0, -, 2, 1, 0, 0]
2
(%i7) qdraw( yr(-1,3),ex1(g(x),x,0,4,lw(5),lc(blue)) )$
which produces
3
2.5
2
1.5
1
0.5
0
-0.5
-1
0
0.5
1.5
2.5
3.5
which produces
3
2.5
2
1.5
1
0.5
0
-0.5
-1
0
0.5
1.5
2.5
3.5
13
The Maxima function integrate cannot handle correctly a function defined with the if, elseif, and else constructs.
(%i9) integrate(g(x),x,0,4);
4
/
[
(%o9) I (if (x > 1) and (x < 2) then x - 1 elseif (x > 2) and (x < 3)
]
/
0
then 6 - 2 x else 0) dx
This means that for now we will have to break up the integration interval into sub-intervals by hand and add up
the individual integral results.
(%i10) integrate(x-1,x,1,2) + integrate(6-2*x,x,2,3);
3
(%o10)
2
(load(draw),load(qdraw) )$
f1(x) := sqrt(x)$
f2(x) := x(3/2)$
qdraw(
xr(-.5,1.5), yr(-.5,1.5),
ex1(f1(x),x,0,1.5,lw(5),lc(blue) ),
ex1(f2(x),x,0,1.5,lw(5),lc(red) ) )$
0.5
-0.5
-0.5
Figure 5:
0.5
14
1.5
Next we redraw this simple plot, but add some shading in color to show the area. The simplest way to do
this is to draw some vertical lines between the functions in the region of interest 0 x 1. We can use the
qdraw package function line. We first construct a list of x axis positions for the vertical lines, using values
0.01, 0.02, ...0.99. We then construct a list vv of the vertical lines and merge that list with a list qdlist
containing the rest of the plot instructions. We then use apply to pass this list as a set of arguments to qdraw.
(%i5) qdlist : [xr(-.5,1.5), yr(-.5,1.5),
ex1(f1(x),x,0,1.5,lw(5),lc(blue) ) ,
ex1(f2(x),x,0,1.5,lw(5),lc(red) ) ]$
(%i6) xv:float(makelist(i,i,1,99)/100)$
(%i7) (vv:[],for x in xv do
vv:cons(line(x,f2(x),x,f1(x),lw(1),lc(khaki) ),vv),
vv:reverse(vv) )$
(%i8) qdlist : append(vv,qdlist)$
(%i9) apply(qdraw, qdlist)$
0.5
-0.5
-0.5
Figure 6:
0.5
1.5
If we did not know the intersection location of the two curves, we could use solve or find_root for example.
(%i10) solve( f1(x) = f2(x),x );
(%o10)
[x = 0, x = 1]
Once we know the interval to use for adding up the area and we know that in this interval f1 (x) > f2 (x), we
simply sum the infinitesimal areas given by (f1 (x) f2 (x)) dx (base dx columns) over the interval 0 x 1.
(%i11) integrate(f1(x) - f2(x),x,0,1);
4
---15
(%o11)
( x x3/2 ) dx = 4/15
15
(7.8)
Example 2
As a second example we consider two polynomial functions:
f1 (x) = (3/10) x5 3 x4 + 11 x3 18 x2 + 12 x + 1
and f2 (x) = 4 x3 + 28 x2 56 x + 32. We first make a simple plot for orientation.
(%i1) f1(x) := (3/10)*x5 -3*x4 + 11*x3 -18*x2 + 12*x + 1$
(%i2) f2(x) := -4*x3 + 28*x2 -56*x + 32$
(%i3) (load(draw),load(qdraw) )$
qdraw(...), qdensity(...), syntax: type qdraw();
(%i4) qdraw(yr(-20,20),ex1(f1(x),x,-1,5,lc(blue) ),
ex1(f2(x),x,-1,5,lc(red)))$
By selecting and copying the grind(..) output, we can use that result to paste in the definition of a function
p(x) which we can then use with find_root.
(%i7) p(x) := 3*x5-30*x4+150*x3-460*x2+680*x-310$
(%i8) x1 : find_root(p(x),x,.7,1);
(%o8)
0.77205830452781
(%i9) x2 : find_root(p(x),x,2.2,2.4);
(%o9)
2.291819210962957
(%i10) x3 : find_root(p(x),x,3.7,3.9);
(%o10)
3.865127100061791
(%i11) map(p, [x1,x2,x3] );
(%o11)
[0.0, 0.0, 9.0949470177292824E-13]
(%i12) [y1,y2,y3] : map(f1, [x1,x2,x3] );
(%o12)
[3.613992056691179, 2.575784006305792, 2.882949345140702]
16
We have checked the solutions by seeing how close to zero p(x) is when x is one of the three roots [x1, x2, x3].
We now split up the integration into the two separate regions where one or the other function is larger.
(%i13) ratprint:false$
(%i14) i1 : integrate(f1(x) - f2(x),x,x1,x2);
41875933
(%o14)
-------7947418
(%i15) i2 : integrate(f2(x)-f1(x),x,x2,x3);
12061231
(%o15)
-------1741444
(%i16) area : i1 + i2;
30432786985
(%o16)
----------2495489252
(%i17) area : float(area);
(%o17)
12.19511843643877
Hence the total area enclosed is about 12.195. Maxima tries to calculate exactly, replacing floating point
numbers with ratios of integers, and the default is to warn the user about these replacements. Hence we have
used ratprint : false$ to turn off this warning.
x2 y 2
+
= 1.
(7.9)
a 2 b2
in which we assume a is the semi-major axis of the ellipse so a > b. In the first quadrant (0 x a and
0 y b), we can solve for y as a function of x :
p
y(x) = b 1 (x/a)2 .
(7.10)
If S is the arc length of the ellipse, then, by symmetry, one fourth of the arclength can be calculated using the
first quadrant integral
s
2
Z a
S
dy
=
1+
dx
(7.11)
4
dx
0
We will start working with the argument of the square root, making a change of variable x z, with x = a z,
so dx = a dz, and a will come outside the integral from the transformation of dx. The integration limits using
the z variable are 0 z 1.
We will then replace the semi-minor axis b by an expression depending on the ellipse eccentricity e, which has
0 < e 1, and whose square is given by
2
b
2
1
(7.12)
e =1
a
(since b < a), so
b = a 1 e2
(%i1) assume(a>0,b>0,a>b,e>0,e<1 )$
(%i2) y:b*sqrt(1 - (x/a)2)$
(%i3) dydx : diff(y,x)$
17
(7.13)
(%i4) e1 : 1 + dydx2;
2 2
b x
(%o4)
----------- + 1
2
4
x
a (1 - --)
2
a
(%i5) e2 : ( subst( [x = a*z,b = a*sqrt(1-e2)],e1 ),ratsimp(%%) );
2 2
e z - 1
(%o5)
--------2
z - 1
(%i6) e3 : (-num(e2))/(-denom(e2));
2 2
1 - e z
(%o6)
--------2
1 - z
(%i7) e4 : dz*sqrt(num(e3))/sqrt(denom(e3));
2 2
dz sqrt(1 - e z )
(%o7)
-----------------2
sqrt(1 - z )
The two substitutions give us expression e2, and we use a desperate device to multiply the top and bottom by
(1) to get e3. We then ignore the factor a which comes outside the integral and consider what is now inside
the integral sign (with the required square root).
We now make another change of variables, with z u, z = sin(u), so dz = cos(u) du. The lower limit
of integration z = 0 = sin(u) transforms into u = 0, and the upper limit z = 1 = sin(u) transforms into
u = /2.
(%i8) e5 : subst( [z = sin(u), dz = cos(u)*du ],e4 );
2
2
du cos(u) sqrt(1 - e sin (u))
(%o8)
-----------------------------2
sqrt(1 - sin (u))
We now use trigsimp but help Maxima out with an assume statement about cos(u) and sin(u).
(%i9) assume(cos(u)>0, sin(u) >0)$
(%i10) e6 : trigsimp(e5);
2
(%o10)
du sqrt(1 - e
2
sin (u))
We then have
Z /2 p
S
=a
1 e2 sin2 u du
(7.14)
4
0
Although integrate cannot return an expression for this integral in terms of elementary functions, in this form
one is able to recognise the standard trigonometric form of the complete elliptic integral of the second kind, (a
18
/2
E(k) = E( = /2, k) =
1 k2 sin2 u du
(7.15)
(7.16)
/2
S = 4 a E(e) = 4 a E(/2, e) = 4 a
p
1 e2 sin2 u du
(7.17)
v2(u)
du
u1
u2
v2(u)
dv f (u, v)
v1(u)
f (u, v) dv
u1
du
(7.18)
v1(u)
19
dy
0
dx
(7.19)
(7.20)
The area will be four times the area of the first quadrant. The first quadrant refers to the region 0 x a
and 0 y b. For a given value of y > 0, the region
p inside the arc of the ellipse in the first quadrant is
determined by 0 x xmax , where xmax = (a/b) b2 y2 . For a given value of x > 0, theregion inside
the arc of the ellipse in the first quadrant is determined by 0 y ymax , where ymax = (b/a) a2 x2 .
One way to find the area of the first quadrant of this ellipse is to sum the values of dA = dx dy by rows,
fixing y and summing over x from 0 to xmax (which depends on the y chosen). That first sum over the x
coordinate accumulates the area of that row, located at y and having width dy. To get the total area (of the first
quadrant) we then sum over rows, by letting y vary from 0 to b.
This method corresponds to the formula
!
Z b Z (a/b) b2 y2
A
=
dx dy.
(7.21)
4
0
0
Here we calculate the first quadrant area using this method of summing over the area of each row.
(%i1)
(%o1)
(%i2)
(%i3)
(%o3)
(%i4)
(%i5)
facts();
[]
assume(a > 0, b > 0, x > 0, x < a, y > 0,y < b )$
facts();
[a > 0, b > 0, x > 0, a > x, y > 0, b > y]
[xmax : (a/b)*sqrt(b2 - y2),ymax : (b/a)*sqrt(a2-x2)]$
integrate( integrate( 1,x,0,xmax), y,0,b );
%pi a b
(%o5)
------4
20
You might think that integrate would not ask for the sign of (y b), or the sign of (x a), since it should
infer that sign from the integration limits. However, the integrate algorithm is super cautious in trying to
never present you with a wrong answer. The general philosophy is that the user should be willing to work with
integrate to assure a correct answer, and if that involves answering questions, then so be it.
The second way to find the area of the first quadrant of this ellipse is to sum the values of dA = dx dy by
columns, fixing x and summing over y from 0 to ymax (which depends on the x chosen). That first sum over
the y coordinate accumulates the area of that column, located at x and having width dx. To get the total area
(of the first quadrant) we then sum over columns, by letting x vary from 0 to a.
This method corresponds to the formula
A
=
4
(b/a)
a2 x2
dy
dx
(7.22)
and is implemented by
(%i6) integrate( integrate( 1,y,0,ymax), x,0,a );
%pi a b
(%o6)
------4
total mass
m
=
total area
ab
(7.23)
Each element of mass dm contributes an amount y2 dm to the moment of inertia Ix , where y is the distance
of the mass element from the x axis. The complete value of Ix is then found by summing this quantity over
the whole elliptical laminate, or because of the symmetry, by summing this quantity over the first quadrant and
multiplying by 4.
Z Z
Z Z
Z Z
2
2
Ix =
y dm =
y dx dy = 4
y2 dx dy
(7.24)
ellipse
ellipse
first quadrant
Hence we have derived Ix = m b2 /4 for the moment of inertia of an elliptical laminate having semi-axes a, b
for rotation about the x axis.
21
Finally, lets use forget to remove our list of assumptions, to show you the types of questions which can
arise. We try calculating the area of the first quadrant, using the method of summing over rows, without any
assumptions provided:
(%i9) forget(a > 0, b > 0, x > 0, x < a, y > 0,y < b )$
(%i10) facts();
(%o10)
[]
(%i11) integrate( integrate(1,x,0,xmax),y,0,b);
Is (y - b) (y + b) positive, negative, or zero?
n;
2
2
Is b - y
positive or zero?
p;
Is b positive, negative, or zero?
p;
%pi a b
(%o11)
------4
assume(b>0)$
integrate( integrate(1,x,0,xmax),y,0,b);
- b) (y + b) positive, negative, or zero?
2
- y
positive or zero?
%pi a b
------4
This may give you some feeling for the value of providing some help to integrate.
assume(a>0,b>0,c>0,a>b,a>c,b>c)$
assume(x>0,x<a,y>0,y<b,z>0,z<c)$
zmax:c*sqrt(1-x2/a2-y2/b2)$
ymax:b*sqrt(1-x2/a2)$
integrate( integrate( integrate(1,z,0,zmax),y,0,ymax),x,0,a );
2 2
2 2
2 2
a y + b x - a b
positive, negative, or zero?
n;
(%o5)
(%i6) vol : 8*%;
(%o6)
%pi a b c
--------6
4 %pi a b c
----------3
To answer the sign question posed by Maxima, we can look at the special case y = 0 and note that since
x2 a2 , the expression will almost always be negative (ie., except for points of zero measure). Hence the
expression is negative for all points interior to the surface of the ellipsoid. We thus have the result that the
volume of an ellipsoid having semi-axes (a, b, c) is given by
V=
4
abc
3
(7.27)
We can now remove the assumption a > b > c, since what we call the x axis is up to us and we could have
chosen any of the principal axis directions of the ellipsoid the x axis.
Of course we will get the correct answer if we integrate over the total volume:
(%i7) [zmin:-zmax,ymin:-ymax]$
(%i8) integrate( integrate( integrate(1,z,zmin,zmax),y,ymin,ymax),x,-a,a );
2 2
2 2
2 2
Is a y + b x - a b
positive, negative, or zero?
n;
(%o8)
4 %pi a b c
----------3
Moment of Inertia
If each small volume element dV = dx dy dz has a mass given by dm = dV, where is the mass density,
and if is a constant, then it is easy to calculate the moment of inertia I3 for rotation of the ellipsoid about the
z axis:
Z Z Z
Z Z Z
2
2
I3 =
(x + y ) dm =
(x2 + y2 ) dx dy dz
(7.28)
where the integration is over the volume of the ellipsoid. The constant mass density is the mass of the
ellipsoid divided by its volume.
23
Here we define that constant density in terms of our previously found volume vol and the mass m, and proceed
to calculate the moment of inertia:
(%i9) rho:m/vol;
3 m
----------4 %pi a b c
(%i10) i3:rho*integrate(integrate(integrate(x2+y2,z,zmin,zmax),
y,ymin,ymax),x,-a,a );
2 2
2 2
2 2
Is a y + b x - a b
positive, negative, or zero?
(%o9)
n;
(%o10)
5 3
7
(8 %pi a b + 8 %pi a b) m
---------------------------5
40 %pi a b
(%i11) ratsimp(i3);
(%o11)
2
2
(b + a ) m
----------5
Hence the moment of inertia for the rotation about the z axis of a solid ellipsoid having mass m, and semi-axes
(a, b, c) is:
I3 = m (a2 + b2 )/5.
(7.29)
24
and we see that Maxima assumes we have enough smoothness in the functions involved to write down the
formal answer in the correct form.
Example 1
We next display a simple example and begin with the simplest case, which is that the limits of integration do
not depend on the parameter y.
(%i3) expr : integrate(x2 + 2*x*y, x,a,b);
b
/
[
2
(%o3)
I (2 x y + x ) dx
]
/
a
(%i4) diff(expr,y);
b
/
[
(%o4)
2 I x dx
]
/
a
(%i5) (ev(%,nouns), ratsimp(%%) );
2
2
(%o5)
b - a
(%i6) ev(expr,nouns);
2
3
2
3
3 b y + b
3 a y + a
(%o6)
----------- - ----------3
3
(%i7) diff(%,y);
2
2
(%o7)
b - a
In the last two steps, we have verified the result by first doing the original integral and then taking the derivative.
Example 2
As a second example, we use an arbitrary upper limit b(y), and then evaluate the resulting derivative expression
for b(y) = y2 .
(%i1) expr : integrate(x2 + 2*x*y, x,a,b(y) );
b(y)
/
[
2
(%o1)
I
(2 x y + x ) dx
]
/
a
25
(%i2) diff(expr,y);
b(y)
(%o2)
/
2
d
[
(b (y) + 2 y b(y)) (-- (b(y))) + 2 I
dy
]
/
x dx
a
(%i3) ( ev(%,nouns,b(y)=y2 ), expand(%%) );
5
4
2
(%o3)
2 y + 5 y - a
(%i4) ev(expr,nouns);
3
2
2
3
b (y) + 3 y b (y)
3 a y + a
(%o4)
----------------- - ----------3
3
(%i5) diff(%,y);
2
d
d
2
3 b (y) (-- (b(y))) + 6 y b(y) (-- (b(y))) + 3 b (y)
dy
dy
2
(%o5)
---------------------------------------------------- - a
3
(%i6) ( ev(%,nouns,b(y)=y2), (expand(%%) );
5
4
2
(%o6)
2 y + 5 y - a
Example 3
An easy example is to derive
d
dt
t2
(2 x + t) d x = 4 t3 + 3 t2 4 t
26
(7.31)
Example 4
Here is an example which shows a common use of the differentiation of an integral with respect to a parameter.
The integral
Z
f1 (a, w) =
x ea x cos(w x) dx
(7.32)
can be done by Maxima with no questions asked, if we tell Maxima that a > 0 and w > 0.
(%i1) assume( a > 0, w > 0 )$
(%i2) integrate(x*exp(-a*x)*cos(w*x),x,0,inf);
2
2
w - a
(%o2)
- ----------------4
2 2
4
w + 2 a w + a
But if we could not find this result directly as above, we could find the result by setting f1 (a, w) = f2 (a, w)/(a),
where
Z
f2 (a, w) =
ea x cos(w x) dx
(7.33)
0
since the differentiation will result in the integrand being multiplied by the factor (x) and produce the negative
of the integral of interest.
(%i3) i1 : integrate(exp(-a*x)*cos(w*x),x,0,inf)$
(%i4) i2 : ev(i1,nouns);
a
(%o4)
------2
2
w + a
(%i5) di2 : (diff(i2,a), ratsimp(%%) );
2
2
w - a
(%o5)
----------------4
2 2
4
w + 2 a w + a
(%i6) result : (-1)*(diff(i1,a) = di2 );
inf
/
2
2
[
- a x
w - a
(%o6)
I
x %e
cos(w x) dx = - ----------------]
4
2 2
4
/
w + 2 a w + a
0
27
where the prime indicates differentiation. This result follows from the product rule of differentiation. This rule
is often stated in the context of indefinite integrals as
Z
Z
0
f (x) g (x) dx = f (x) g(x) f 0 (x) g(x) dx
(7.35)
or in an even shorter form, with u = f (x), du = f 0 (x) dx, v = g(x), and dv = g0 (x) dx, as
Z
Z
u dv = u v v du
(7.36)
In practice, we are confronted with an integral whose integrand can be viewed as the product of two factors,
which we will call f (x) and h(x):
Z
f (x) h(x) dx
(7.37)
and we wish to use integration by parts to get an integral involving the derivative of the first factor, f (x), which
will hopefully result in a simpler integral. We then identify h(x) = g0 (x) and solve this equation for g(x) (by
integrating; this is also a choice based on the ease of integrating the second factor h(x) in the given integral).
Having g(x) in hand we can then write out the result using the indefinite integral integration by parts rule
above. We can formalize this process for an indefinite integral with the Maxima code:
(%i1) iparts(f,h,var):= block([g ],
g : integrate(h,var),
f*g - integrate(g*diff(f,var),var ) )$
R
Lets practice with the integral x2 sin(x) dx, in which f (x) = x2 and h(x) = sin(x), so we need to be able
to integrate sin(x) and want to transfer a derivative on to x2 , which will reduce the first factor to 2 x. Notice
that it is usually easier to work with Maxima expressions rather than with Maxima functions in a problem
like this.
(%i2) iparts(x2,sin(x),x);
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
/
[
2
2 I x cos(x) dx - x cos(x)
]
/
(ev(%,nouns),expand(%%) );
2
2 x sin(x) - x cos(x) + 2 cos(x)
collectterms(%,cos(x) );
2
2 x sin(x) + (2 - x ) cos(x)
If we were not using Maxima, but doing everything by hand, we would use two integrations by parts (in
succession) to remove the factor x2 entirely, reducing the original problem to simply knowing the integrals of
sin(x) and cos(x).
28
Of course, with an integral as simple as this example, there is no need to help Maxima out by integrating by
parts.
(%i5) integrate(x2*sin(x),x);
(%o5)
2
2 x sin(x) + (2 - x ) cos(x)
We can write a similar Maxima function to transform definite integrals via integration by parts.
(%i6) idefparts(f,h,var,v1,v2):= block([g ],
g : integrate(h,var),
subst(v2,var, f*g) - subst(v1,var, f*g ) integrate(g*diff(f,var),var,v1,v2 ) )$
(%i7) idefparts(x2,sin(x),x,0,1);
1
/
[
2
(%o7) 2 I x cos(x) dx + substitute(1, x, - x cos(x))
]
/
0
2
- substitute(0, x, - x
cos(x))
(%i8) (ev(%,nouns),expand(%%) );
(%o8)
2 sin(1) + cos(1) - 2
(%i9) integrate(x2*sin(x),x,0,1);
(%o9)
2 sin(1) + cos(1) - 2
29
Example 1
Here we use this Maxima function on the simple indefinite integral
hand:
The original indefinite integral is a function of x, which we obtain by replacing u by its equivalent as a function
of x. We have shown three ways to make this replacement to get a function of x, using subst and ratsubst.
Example 2
As a second example, we use a change of variables to find
30
(x + 2)/ x + 1 dx.
(%o8)
(%o9)
(%i10) subst(u = sqrt(x+1),%);
(%o10)
3/2
2 (x + 1)
------------ + 2 sqrt(x + 1)
3
Of course Maxima can perform the original integral in these two examples without any help, as in:
(%i11) integrate((x+2)/sqrt(x+1),x);
3/2
(x + 1)
(%o11)
2 (---------- + sqrt(x + 1))
3
However, there are occasionally cases in which you can help Maxima find an integral ( for which Maxima can
only return the noun form) by first making your own change of variables and then letting Maxima try again.
Example 3
Here we use changevar with a definite integral, using the same integrand as in the previous example. For
a definite integral, the variable of integration is a dummy variable, and the result is not a function of that
dummy variable, so there is no issue about replacing the new integration variable u by the original variable x
in the result.
(%i12) expr : integrate( (x+2)/sqrt(x+1),x,0,1);
1
/
[
x + 2
(%o12)
I ----------- dx
] sqrt(x + 1)
/
0
31
(%o13)
/
[
I
]
/
2
(2 u
+ 2) du
1
(%i14) ev(%, nouns);
(%o14)
10 sqrt(2)
8
---------- - 3
3
Example 4
We next discuss an example which shows that one needs to pay attention to the possible introduction
R 1 y2 of obvious
sign errors when using changevar. The example is the evaluation of the definite integral 0 e dy, in which
y is a real variable. Since the integrand is a positive (real) number over the interval 0 < y 1, the definite
integral must be a positive (real) number. The answer returned directly by Maximas integrate function is:
(%i1) fpprintprec:8$
(%i2) i1:integrate (exp (y2),y,0,1);
sqrt(%pi) %i erf(%i)
(%o2)
- -------------------2
- 0.886227 %i erf(%i)
so we see if we can get a numerical value from erf(%i) by multiplying %i by a floating point number:
(%i4) erf(1.0*%i);
(%o4)
1.6504258 %i
so to get a numerical value for the integral we use the same trick
(%i5) float(subst(1.0*%i,%i,i1));
(%o5)
1.4626517
Maximas symbol erf(z) represents the error function Erf (z). We have discussed the Maxima function erf(x)
for real x in Example 4 in Sec.(7.2). Here we have a definite integral result returned in terms of erf(%i),
which is the error function with a pure imaginary agument and we have just seen that erf(%i) is purely
imaginary with an approximate value 1.65*%i.
We can confirm the numerical value of the integral i1 using the quadrature routine quad_qags:
(%i6) quad_qags(exp(y2),y,0,1);
(%o6)
[1.4626517, 1.62386965E-14, 21, 0]
32
though there are two solutions y = u, Maxima picks the wrong solution without asking the user a clarifying
question. We need to force Maxima to use the correct relation between y and u, as in:
(%i11) changevar(expr,y-sqrt(u),u,y);
Is y positive, negative, or zero?
pos;
1
/
[
I
]
/
(%o11)
u
%e
------- du
sqrt(u)
0
------------2
33
Example 5
We now discuss an example of a change of variable in which changevarR produces
overall sign, even
the wrong
sqrt(x
- 4)
Since we have assumed t > 0, we have tan(t) > 0, so changevar is telling us the indefinite integral is a negative number for the range of t assumed.
Since we are asking for an indefinite integral, and we want the result in terms of the original variable x, we
would need to do some more work on this answer, maintaing the assumptions we have made. We will do that
work after we have repeated this change of variable, doing it by hand.
34
which is the result changevar should have produced. Now lets show how we can get back to the indefinite
integral produced the direct use of integrate.
(%i12) subst(tan(t)= sqrt(sec(t)2-1),2*tan(t) );
2
(%o12)
2 sqrt(sec (t) - 1)
(%i13) subst(sec(t)=1/cos(t),%);
1
(%o13)
2 sqrt(------- - 1)
2
cos (t)
(%i14) subst(cos(t)=2/x,%);
2
x
(%o14)
2 sqrt(-- - 1)
4
(%i15) ratsimp(%);
2
(%o15)
sqrt(x - 4)
This concludes our discussion of a change of variable of integration and our discussion of symbolic integration.
35
Preface
COPYING AND DISTRIBUTION POLICY
This document is part of a series of notes titled
"Maxima by Example" and is made available
via the authors webpage http://www.csulb.edu/woollett/
to aid new users of the Maxima computer algebra system.
NON-PROFIT PRINTING AND DISTRIBUTION IS PERMITTED.
You may make copies of this document and distribute them
to others as long as you charge no more than the costs of printing.
These notes (with some modifications) will be published in book form
eventually in an arrangement which will continue
to allow unlimited free download of the pdf files as well as the option
of ordering a low cost paperbound version of these notes.
Feedback from readers is the best way for this series of notes to become more helpful to new users of Maxima.
All comments and suggestions for improvements will be appreciated and carefully considered.
The Maxima session transcripts were generated using the Xmaxima
graphics interface on a Windows XP computer, and copied into
a fancy verbatim environment in a latex file which uses the
fancyvrb and color packages.
The author would like to thank the Maxima developers for their friendly help via the Maxima mailing list.
Richard Fateman provided early encouragement and advice. Raymond Toy, Stavros Macrakis, and Barton
Willis have each contributed importantly to the evolution of the code in the nint package.
The present nint and apnint packages are a work in progress, partially dictated by the progress in Maxima
special function float and bfloat values. The new Ch. 8 functions apnint and apquad are the first step in
providing quadrature results which attempt to satisfy user requested precision (for one dimensional quadrature).
8.1
Introduction
8.2 Using nint and quad for One or Two Dimensional Quadrature
8.2.1 Loading the nint Package
Maxima will be ready to use the nint package once you have issued a load command such as load(nint)
(if you have set up your maxima.init file as suggested in Ch. 1), or, using a complete path, as in
load("c:/work2/nint.mac").
(%i1) load(nint);
(%o1) "c:/work2/nint.mac"
The files that are loaded are nint.mac, nint.lisp, quad_util.mac, mydefint.mac, quad1d.mac,
and quad2d.mac. Global parameters which are set during this load are: display2d:false,
ratprint:false, domain:complex, and lognegint:true.
8.2.2 nint and quad Syntax
Here is a summary of the syntax for either nint or quad.
We use var for the variable of integration, and a and b for the range limits in the 1d examples here (naturally,
you can use any symbol for the variable of integration, as long as the supplied expression expr is a function
of that variable.
For the 2d syntax examples, we assume expr is a function of x and y, with x1 and x2 the range limits for the
x variable, and with y1 and y2 the range limits for the y variable.
Again, you can use any symbols for the variables of integration.
The range limit parameters are either real numbers or inf or minf.
1D INTEGRAL SYNTAX
To first try integrate with a fallback to quadpack:
nint ([expr],var,a, b [options])
or, to force use of quadpack:
quad ([expr],var,a, b [options])
The options: strong_osc, singular, principal_val(v0), points(x1,x2,...), real,
imaginary, and complex are recognised for one dimensional integrals and are used to decide what quadpack routine to use and how.
Before calling the quadpack routines, nint (or quad) expends some effort in trying to confirm that the integrand is either real or pure imaginary. If nint (or quad) cannot assume the integrand is either real or pure
imaginary (using a series of tests), nint (or quad) proceeds to work with the real and imaginary parts separately. Although it is never necessary to use the options real, imaginary, or complex, for a complicated
integrand some time may be saved if the relevant option is included (thus avoiding the time for the tests). Of
course, if you include the option real, you should be sure the integrand evaluates to a real number over the
whole domain of integration!
The option strong_osc forces use of quad_qag if integrate does not succeed. The strong_osc keyword should only be used for a finite interval of integration.
5
The option singular forces use of quad_qags if integrate does not succeed; should only be used for a
finite interval of integration.
The option principal_val(v0) assumes that expr has the form g(var)/(var - v0), and requests
that the quadpack routine quad_qawc be used for a numerical principal value evaluation (if integrate is not
used or is not successful).
The option points(x1,x2,..) forces use of quad_qagp if integrate is not used or is not successful.
quad_qagp gives special treatment to the supplied points, where the integrand is assumed to have singular
behavior of some type. The supplied points should be entirely inside the range of integration.
1d examples ( in each you can use quad instead of nint,
which forces use of quadpack routines ):
nint
nint
nint
nint
(expr,var,a,b)
(expr,var,a,b,real)
(expr,var,a,b,imaginary)
(expr,var,a,b,complex)
nint
nint
nint
nint
(expr,var,a,b,strong_osc)
(expr,var,a,b,strong_osc,real)
(expr,var,a,b,strong_osc,imaginary)
(expr,var,a,b,strong_osc,complex)
nint
nint
nint
nint
(expr,var,a,b,singular)
(expr,var,a,b,singular,real)
(expr,var,a,b,singular,imaginary)
(expr,var,a,b,singular,complex)
nint (expr,var,a,b,principal_val(v0))
where v0 evaluates to a number and
a < v0 < b.
nint (expr,var,a,b,principal_val(v0),real)
nint (expr,var,a,b,principal_val(v0),imaginary)
nint (expr,var,a,b,principal_val(v0),complex)
nint (expr,var,a,b, points(x1,x2,...))
where x1, x2, etc., evaluate to numbers and
a < x1 < b, etc.
nint (expr,var,a,b, points(x1,x2,...),real)
nint (expr,var,a,b, points(x1,x2,...),imaginary)
nint (expr,var,a,b, points(x1,x2,...),complex)
6
2D INTEGRAL SYNTAX
We use a 2d notation similar to Mathematicas. nint(f,[x,x1,x2],[y,y1,y2]) is the approximate
numerical value of the double integral integrate( integrate (f,y,y1,y2), x,x1,x2). The 2d
quadrature syntax is then:
nint (expr,[x,x1,x2 [x-option]],[y,y1,y2 [y-option]] [gen-option])
which includes a try using integrate, or
quad (expr,[x,x1,x2 [x-option]],[y,y1,y2 [y-option]] [gen-option])
which uses only the quadpack routines. For example (in each, you can replace nint by quad):
nint (expr,[x,x1,x2],[y,y1,y2])
nint (expr,[x,x1,x2],[y,y1,y2],real)
nint (expr,[x,x1,x2],[y,y1,y2,strong_osc])
nint (expr,[x,x1,x2,strong_osc],[y,y1,y2],imaginary)
nint (expr,[x,x1,x2],[y,y1,y2,principal_val(y0)])
nint (expr,[x,x1,x2],[y,y1,y2,points(ya,yb,...)])
GENERAL REMARKS
nint calls nint1d for a 1d integral or nint2d for a 2d integral. nint1d and nint2d are responsible for making sure the work detail lists nargL and noutL are constructed and available as global lists if
integrate is used and is successful.
Otherwise these lists are constructed by the code in quad1d or quad2d, which are called if the word nint
is replaced by quad, or which are called if the call to integrate (by nint) is not sucessful.
nargL is a global list of method and args input, noutL is a global list of method and either integrate or
quadpack total output.
If method is set to true, nint or quad will print out the method used during the work.
If debug is set to true, many details of progress will be printed to the console screen.
8.2.3 1D Quadrature Using mdefint and ndefint
You might want to try using (i.e., force Maxima to use) integrate, even though nint avoids using
integrate for a particular integrand.
For 1d integrals, the package provides the function mdefint which uses integrate (in a careful way) to try
to get a symbolic answer. You can then use cfloat to reduce the answer to a floating point value. cfloat
is a package function which combines rectform, float, and expand in one function, with the definition:
cfloat(expr):= (expand(float(rectform(expr))))$
However, if the symbolic answer is the difference of two almost equal values, cfloat can return an incorrect
numerical value. A more careful reduction to a numerical value occurs with the use of the package function
fbfloat (expr, ndigits) which uses bigfloat methods to reduce expr to a floating point value using
the requested precision.
The package function ndefint combines mdefint with fbfloat and requests 32 digit accuracy. Some
examples of the use of mdefint and ndefint for 1d quadrature (see below for 2d examples):
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
(%o8)
load(nint);
"c:/work2/nint.mac"
mdefint(log(1/x)/sqrt(x),x,0,1);
4
ndefint(log(1/x)/sqrt(x),x,0,1);
4.0
mdefint(log(1/x)/sqrt(%i*x),x,0,1);
-4*(-1)(3/4)
ndefint(log(1/x)/sqrt(%i*x),x,0,1);
2.82842712474619-2.82842712474619*%i
mdefint(log(1/x)/sqrt(%i*x),x,0,1);
-4*(-1)(3/4)
cfloat(%);
2.828427124746191-2.828427124746191*%i
fbfloat(%o6,32);
2.82842712474619-2.82842712474619*%i
load(nint);
"c:/work2/nint.mac"
nint(log(1/x)/sqrt(%i*x),x,0,1);
2.82842712474623-2.828427124746158*%i
noutL;
[[qags,2.82842712474623,3.6770586575585185E-13,315,0],
[qags,-2.828427124746158,1.1102230246251565E-13,315,0]]
(%i4) quad(log(1/x)/sqrt(%i*x),x,0,1);
(%o4) 2.82842712474623-2.828427124746158*%i
(%i5) noutL;
(%o5) [[qags,2.82842712474623,3.6770586575585185E-13,315,0],
[qags,-2.828427124746158,1.1102230246251565E-13,315,0]]
(%i6) method:true$
(%i7) nint(log(1/x)/sqrt(%i*x),x,0,1);
quad_qags
quad_qags
(%o7) 2.82842712474623-2.828427124746158*%i
(%i8) quad(log(1/x)/sqrt(%i*x),x,0,1);
quad_qags
quad_qags
(%o8) 2.82842712474623-2.828427124746158*%i
(%i9) noutL;
(%o9) [[qags,2.82842712474623,3.6770586575585185E-13,315,0],
[qags,-2.828427124746158,1.1102230246251565E-13,315,0]]
(%i10) nint(x2,x,0,2);
integrate
(%o10) 2.666666666666667
(%i11) mdefint(x2,x,0,2);
(%o11) 8/3
(%i12) cfloat(%);
(%o12) 2.666666666666667
In the last example, integrate is able to find the result, but quadpack fails. The symbolic answer is:
(%i16) mdefint(exp (%i*x2),x,minf,inf);
(%o16) sqrt(%pi)*(%i/sqrt(2)+1/sqrt(2))
Further Examples
Because the integrand contains sqrt, nint bypasses integrate here and calls quad1d. However,
integrate can actually do this integral and returns the correct numerical value.
(%i17) nint(sin(x)/sqrt(x),x,0,5000,real,singular);
quad_qags
(%o17) 1.251128192999518
(%i18) ndefint(sin(x)/sqrt(x),x,0,5000);
(%o18) 1.251128192999533
9
Here is a principal value integral done by quadpack:
(%i20) quad((x-x2)(-1),x,-1/2,1/2,principal_val(0));
quad_qawc
quad_qawc
(%o20) 1.09861228866811
However, integrate can do this principal value integral, and issues the Principal Value printout to warn
the user:
(%i21) ndefint((x-x2)(-1),x,-1/2,1/2);
Principal Value
(%o21) 1.09861228866811
Here is a quadrature done using the quadpack routine quad_qagp by including the points option:
(%i22) quad(1/sqrt(sin(x)),x,0,10,points(%pi,2*%pi,3*%pi));
quad_qagp
quad_qagp
quad_qagp
(%o22) 10.48823021716681-6.769465521725387*%i
ndefint(1/sqrt(sin(x)),x,0,10);
false
mdefint(1/sqrt(sin(x)),x,0,10);
integrate(1/sqrt(sin(x1030868)),x1030868,0,10)
load(nint);
"c:/work2/nint.mac"
nint(1,[x,0,1],[y,0,1]);
1.0
quad(1,[x,0,1],[y,0,1]);
1.0
mdefint(1,[x,0,1],[y,0,1]);
1
ndefint(1,[x,0,1],[y,0,1]);
1.0
nint(1/sqrt(x+y),[x,0,1],[y,0,1],real);
1.104569499660576
nint(sin(x*y),[x,0,1],[y,0,1],real);
0.23981174200056
10
A 2d example in which the presence of log and also fractional powers causes integrate to be bypassed
in favor of quadpack (set method to true to see easily what method is being used here):
(%i8) method:true$
(%i9) nint(log(y)/x(4/5),[x,0,1],[y,0,1]);
qags2
(%o9) -5.000000000000004
(%i10) time(%);
(%o10) [6.23]
(%i11) nint(log(y)/x(4/5),[x,0,1],[y,0,1],real);
qags2
(%o11) -5.000000000000004
(%i12) time(%);
(%o12) [3.78]
(%i13) ndefint(log(y)/x(4/5),[x,0,1],[y,0,1]);
(%o13) -5.0
(%i14) time(%);
(%o14) [0.02]
This is a case in which including the option real halves the time of the quadpack calculation. This integranddomain combination is correctly evaluated by mdefint in a fraction of the time required by quadpack.
(%i15)
(%o15)
(%i16)
(%o16)
mdefint(log(y)/x(4/5),[x,0,1],[y,0,1]);
-5
time(%);
[0.0]
load(nint);
"c:/work2/nint.mac"
domain;
complex
11
8.2.7 Case: Symbolic Definite Integral the Difference of Two Almost Equal Numbers
Here we compare the direct use of integrate, nint, and quad with an integrand whose definite integral is the
difference of two almost equal numbers.
Use of cfloat (an nint package function which combines rectform, float, and expand) produces a
wildly wrong numerical answer. Use of the package function fbfloat, and choice of 32 digit precision, uses
bigfloat methods to get an accurate answer, which is then converted back to 16 digit display inside the function
fbfloat.
The package function fchop is used routinely in the package to ignore very small numbers.
The package function nint tries integrate first, and if successful then uses fbfloat with 32 digit precision requested to obtain the numerical value from the symbolic definite integral, and then uses fchop.
The package function quad always uses fchop on the result returned by quadpack to round off the numerical
answer. (But see below about turning off the chopping of very small numbers.)
It is clear, from the nature of the integrand, that the answer must be a real number.
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
(%o8)
(%i9)
(%o9)
load(nint);
"c:/work2/nint.mac"
ee : integrate(exp(x5),x,1,2);
((-1)(4/5)*gamma_incomplete(1/5,-32)-(-1)(4/5)
*gamma_incomplete(1/5,-1))/5
cfloat(ee);
1.0132394896940175E+12-1.9531250000000001E-4*%i
fbfloat(ee,32);
1.0512336862202133E-20*%i+1.0132394896940183E+12
fchop(%);
1.0132394896940183E+12
nint(exp(x5),x,1,2);
1.0132394896940183E+12
noutL;
[integrate,1.0132394896940183E+12]
quad(exp(x5),x,1,2);
1.0132394896940144E+12
noutL;
[qag,1.0132394896940144E+12,0.011249218166387,155,0]
In the above output, the global parameter noutL includes the method and the result(s) returned by the method.
12
The global parameter nargL is a list which includes both the method and the arguments used by the method.
The names of the integration variables actually used are automatically generated by the code to allow global
assumptions to remain in force after the computation, hence the weird names.
(%i10)
(%o10)
(%i11)
(%o11)
(%i12)
(%o12)
(%i13)
(%o13)
nint(exp(x5),x,1,2);
1.0132394896940183E+12
nargL;
[integrate,%ewx623755,wx62375,1,2]
quad(exp(x5),x,1,2);
1.0132394896940144E+12
nargL;
[qag,%ex760145,x76014,1.0,2.0,3,limit = 800]
load(nint);
"c:/work2/nint.mac"
dochop;
true
nint(exp(x5),x,1,2);
1.0132394896940183E+12
dochop:false$
nint(exp(x5),x,1,2);
1.0512336862202133E-20*%i+1.0132394896940183E+12
dochop:true$
nint(exp(x5),x,1,2);
1.0132394896940183E+12
13
8.3 Arbitrary Precision One Dimensional Quadrature with apnint and apquad
Syntax
The new Ch. 8 functions apnint (arbitrary precision numerical integration which first tries integrate) and
apquad (arbitrary precision quadrature which avoids integrate) are defined in the file apnint.mac (which
loads tsquad.mac and dequad.mac). To use apnint and/or apquad, you should first load the
nint.mac package, and then the apnint.mac package.
Both functions have the same syntax:
apnint (expr, x, x1,x2,rp,wp)
apquad (expr, x, x1,x2,rp,wp)
in which expr depends on the variable x (of course you can use any symbol), x1 is less than x2, x1 must
evaluate to a finite real number, but x2 can either be finite (evaluating to a real number) or the symbol inf.
rp is the requested precision (precision goal, the number of trustworthy digits wanted in the result), and
wp is the working precision (fpprec is set to wp during the course of the calculation).
These two functions do not set values of noutL and nargL, but you can set method to true to have a short
printout of the method used. The finite numerical case uses a new function tsquad (which accepts a complex
integrand), defined in the file tsquad.mac.
The non-finite numerical case uses a new function dequad (which also accepts a complex integrand), defined
in the file dequad.mac.
Both of these new functions return the result as a bigfloat number. In general, bfloat(expr) returns a
bigfloat number whose precision depends on the current value of fpprec. Both package functions apnint
and apquad worry about setting the value of fpprec locally to the values needed corresponding to the wp
arg. You do not have to set the global value of fpprec yourself, although that global value will not affect the
precision of the calculation: only the supplied value wp affects the precision of the actual calculation.
Here are some examples of bigfloat number returns (the default value of fpprec is 16). When comparing
two bigfloat numbers, you should set the value of fpprec to a large enough value. Using float to convert a
bigfloat number to an ordinary floating point number leads to a loss of significant digits. (See Ch. 9 for more
discussion of bigfloats.)
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
(%o7)
fpprec;
16
pi16 : bfloat(%pi);
3.141592653589793b0
pi30 : bfloat(%pi),fpprec:30;
3.14159265358979323846264338328b0
fpprec;
16
abs(pi16 - pi30);
0.0b0
abs(pi16 - pi30),fpprec:40;
1.144237745221949411169021904042519539695b-17
pi30f : float(pi30);
3.141592653589793
14
An Accuracy Test
A test used in Ch.9 is the known integral
Z
t ln(t) dt = 4/9
(8.1)
You need to load both the nint.mac package, and then the apnint package (the latter loads tsquad.mac
and dequad.mac).
(%i1) (load(nint),load(apnint));
_kmax% = 8
_epsfac% = 2
(%o1) "c:/work2/apnint.mac"
(%i2) integrate(sqrt(x)*log(x),x,0,1);
(%o2) -4/9
(%i3) tval : bfloat(%),fpprec:45;
(%o3) -4.44444444444444444444444444444444444444444445b-1
(%i4) apval : apquad(sqrt(x)*log(x),x,0,1,30,40);
construct _yw%[kk,fpprec] array for kk =
8 and fpprec = 40
...working...
(%o4) -4.444444444444444444444444444444444444445b-1
(%i5) abs(apval - tval),fpprec:45;
(%o5) 4.46422161518439410412204461320543256312937649b-41
Requesting thirty digit accuracy with forty digit arithmetic returns a value for this integral which has about
forty digit precision. See Ch.9 for other tests using known integrals.
The loading of the apnint.mac file causes the loading of other files of the package. The loading of the
package file tsquad.mac produces the printout: _kmax% = 8
_epsfac% = 2 seen in the above
example, which warns that two global parameters are set by the package. Ch.9 discusses the meaning of those
parameters, and the possibility of changing them to fit your special problem.
An array of transformation coefficients is constructed, using 40 digit arithmetic, in the above example. Once
that array has been constructed, other numerical integrals can be evaluated using the same set of coefficients
(as long as the same working precision wp is requested).
If you change the value of wp, a new array of coefficients is constructed, which is available for use with other
integrals (the original 40 digit array is still available also).
(%i6) apquad(sqrt(x)*log(x),x,0,1,20,30);
construct _yw%[kk,fpprec] array for kk =
8 and fpprec = 30
...working...
(%o6) -4.44444444444444444444444444445b-1
(%i7) apquad(sqrt(x)*log(x),x,0,1,30,40);
(%o7) -4.444444444444444444444444444444444444445b-1
15
Some Examples
Using apquad forces use of a numerical method discussed in Ch.9, instead of first trying integrate. The
expr to be integrated can be complex.
(%i8) apquad(sin(x)*exp(%i*x),x,0,2,20,30);
(%o8) 1.18920062382698206284315977363b0*%i+4.13410905215902978659792045774b-1
However this integral can be done using integrate, and Maxima is successful in obtaining a bfloat value
of the symbolic result:
(%i9) method:true$
(%i10) apnint(sin(x)*exp(%i*x),x,0,2,20,30);
integrate
(%o10) 1.18920062382698206284315977363b0*%i+4.13410905215902978659792045774b-1
Here is an example of a non-finite integral with a complex integrand. We force use of a numerical method by
using apquad:
(%i11) apquad(exp(-x +%i*x),x,0,inf,20,30);
dequad
(%o11) 5.0b-1*%i+5.0b-1
The package function dequad is defined in the file dequad.mac, loaded by apnint.mac, and can handle
a complex integrand, passing the real and imaginary parts separately to the Ch.9 function quad_de (the latter
assumes a real integrand).
As in the previous example, using apnint produces an answer from integrate:
(%i12) apnint(exp(-x +%i*x),x,0,inf,20,30);
integrate
(%o12) 5.0b-1*%i+5.0b-1
Here is an example of an integrand containing a Bessel function, and integrate cannot find the definite
integral over the non-finite domain, nor can integrate find the indefinite integral:
(%i13)
(%o13)
(%i14)
(%o14)
integrate(bessel_j(1,x)*exp(-x),x,0,inf);
integrate(bessel_j(1,x)*%e-x,x,0,inf)
integrate(bessel_j(1,x)*exp(-x),x);
integrate(bessel_j(1,x)*%e-x,x)
If we force the use of the numerical bigfloat methods, the integrand is first tested to see if evaluation at a bigfloat
specified point returns a bigfloat number, and for this example the Bessel function factor is not reduced:
(%i15) bfloat(bessel_j(1,0.5b0)*exp(-0.5b0));
(%o15) 6.065306597126334b-1*bessel_j(1.0b0,5.0b-1)
The presence of sqrt and/or log in an integrand causes apnint to bypass integrate, (just as happens
with nint).
(%i17) apnint(log(1/x)/sqrt(%i*x),x,0,1,20,30);
tsquad
(%o17) 2.82842712474619009760337744842b0-2.82842712474619009760337744842b0*%i
16
Here is an example of a complex integrand in which quad can get a numerical answer (about 15 digit
precision), but apquad can only get an answer for the realpart of the integrand:
(%i18) quad(log(-3+%i*x),x,-2,3);
quad_qag
quad_qags
(%o18) 2.449536971144524*%i+6.02070929514083
(%i19) quad(realpart(log(-3+%i*x)),x,-2,3);
quad_qag
(%o19) 6.02070929514083
(%i20) quad(imagpart(log(-3+%i*x)),x,-2,3);
quad_qags
(%o20) 2.449536971144524
(%i21) apnint(realpart(log(-3+%i*x)),x,-2,3,20,30);
tsquad
(%o21) 6.02070929514083135694888711387b0
(%i22) apnint(imagpart(log(-3+%i*x)),x,-2,3,20,30);
quad_ts: vdiffnew > vdiffold before vdiff < eps0 reached
quad_ts: abort calc.
(%o22) false
(%i23) imagpart(log(-3+%i*x));
(%o23) atan2(x,-3)
The bigfloat calculation for the imaginary part of the integrand was aborted when the differences between the
current estimate and the previous estimate of the integral started growing (instead of decreasing steadily).
integrate(cos(x),x,0,1);
sin(1)
float(%);
0.8414709848079
17
produces a numerical result corresponding to Maximas
float(integrate(cos(x),x,0,1))
Mathematica also has the function N which computes the numerical value of expr with the syntax:
N[ expr ]
or
expr //N
Two examples of numerical two dimensional integration in Mathematica syntax are:
NIntegrate[1/Sqrt[x + y], {x,0,1},{y,0,1} ]
NIntegrate[Sin[ x*y ],{x,0,1}, {y,0,1} ]
8.5 Direct Quadpack Use of quad qags, quad qag, and quad qagi
The quadpack subroutine package originally was a set of Fortran subroutines, described in the book:
Quadpack: A Subroutine Package for Automatic Integration,
by R. Piessens, E. de Doncker-Kapenga, C.W. Uberhuber,
and D.K. Kahaner,
Springer-Verlag, 1983
and designed for the computation of 1d integrals. The Maxima developer Raymond Toy has adapted the package to Maxima via a translation from Fortran to Common Lisp (using f2cl) combined with a special interface
for the Maxima user.
See the Maxima Help Manual for an extensive discussion in Sec. 19.3 (Sec. 19 is Integration).
8.5.1 Syntax for Quadpack Functions
The integrand expr supplied as the first argument to a quadpack function must evaluate to a real number
throughout the requested range of the independent variable. All the quadpack functions (q is for quadrature), except two, are called using the syntax:
quad_qaxx ( expr, var, a, b, (other-required-args), optional-args)
exceptions are the Cauchy principle value integration routine quad_qawc which does the integral
RThe
b
f (x)/(x c) dx, using the syntax quad_qawc(expr,var,c,a,b,optional-args),
a
and
R the cosine or sine Fourier
R transform integration routine quad_qawf which does integrals
f (x) cos( x) dx or a f (x) sin( x) dx using the syntax
a
quad_qawf(expr,var,a,omega,trig,optional-args).
18
8.5.2 Ouput List of Quadpack Functions and Error Code Values
All Quadpack functions return a list of four elements:
[num-val, est-abs-error, number-integrand-evaluations, error-code].
The error-code (the fourth element of the returned list) can have the values:
0 - no problems were encountered
1 - too many sub-intervals were done
2 - excessive roundoff error is detected
3 - extremely bad integrand behavior occurs
4 - failed to converge
5 - integral is probably divergent or slowly convergent
6 - the input is invalid
8.5.3 Integration Rule Parameters and Optional Arguments
All the Quadpack functions (except one) include epsrel, epsabs, and limit as possible optional types of allowed
arguments to override the default values of these parameters: epsrel = 1e-8, epsabs = 0.0, limit = 200.
To override the epsrel default value, for example, you would add the optional argument epsrel = 1e-6 or
epsrel=1d-6 (both have the same effect).
These Quadpack functions apply an integration rule adaptively until an estimate of the integral of expr over
the interval (a, b) is achieved within the desired absolute and relative error limits, epsabs and epsrel. With
the default values epsrel = 1e-8, epsabs = 0.0, only epsrel plays a role in determining the convergence of the
integration rules used, and this corresponds to getting the estimated relative error of the returned answer smaller
than epsrel.
If you override the defaults with the two optional arguments (in any order) epsrel = 0.0, epsabs = 1e-8, for
example, the value of epsrel will be ignored and convergence will have been achieved if the estimated absolute
error is less than epsabs.
The integration region is divided into subintervals, and on each iteration the subinterval with the largest estimated error is bisected. This adaptive method reduces the overall error rapidly, as the subintervals become
concentrated around local difficulties in the integrand.
The Quadpack parameter limit, whose default value is 200, is the maximum number of subintervals to be
used in seeking a convergent answer. To increase that limit, you would insert limit=300, for example.
19
8.5.4 quad qags for a Finite Interval
The s on the end of qags is a signal that quad_qags has extra abilities in dealing with functions which
have integrable singularities, but even if your function has no singular behavior, quad_qags is still the best
choice due to the sophistication of the quadrature algorithm used. Use the syntax
quad_qags ( expr, var , a, b, [ epsrel, epsabs, limit ] )
where the keywords inside the brackets indicate possible optional arguments (entered in any order), such as
epsrel = 1e-6.
R1 2
Thus the approximate numerical value of 0 ex dx would be the first element of the list returned by
quad_qags (exp (x2), x, 0, 1).
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
display2d:false;
false
domain;
real
quad_qags(exp (x2),x,0,1);
[1.462651745907182,1.6238696453143376E-14,21,0]
If you call quad_qags with an unbound parameter in the integrand, a noun form will be returned which will
tell you all the defaults being used.
(%i4) quad_qags(a*x,x,0,1);
(%o4) quad_qags(a*x,x,0,1,epsrel = 1.0E-8,epsabs = 0.0,limit = 200)
(8.2)
where > 1 and > 1 for convergence. See Sec 8.6.3 for more information on quad_qaws and its use.
Example 1
R1
Here is an example of the use of quad_qags to compute the numerical value of the integral 0 x ln(1/x) dx.
The integrand g = x1/2 ln(1/x) = x1/2 ln(x) has the limiting value 0 as x 0 from the positive side. Thus
the integrand is not singular at x = 0, but it is rapidly changing near x = 0 so an efficient algorithm is needed.
(Our Example 2 will work with an integrand which is singular at x = 0.)
Lets check the limit at x = 0 and plot the function.
(%i5)
(%i6)
(%o6)
(%i7)
(%i8)
g:sqrt(x)*log(1/x)$
limit(g,x,0,plus);
0
(load(draw),load(qdraw))$
qdraw( ex(g,x,0,1) )$
20
Here is that plot.
1
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0.2
0.4
0.6
0.8
The first element of the returned list qlist is the approximate numerical value of the integral. We have used
integrate together with bfloat and fpprec to generate the true value good to about 20 digits (see Chapter 9),
and we see that the absolute error of the answer returned by quad_qags is about 1016 . The second element
of qlist is the estimated absolute error of the returned answer. The third element shows that 315 integrand
evaluations were needed to attain the requested (default) relative error epsrel = 1e-8. The fourth element is the
error code value 0 which indicates no problems were found.
The algorithm used to find an approximation for this integral does not know the exact (or true) answer, but
does have (at each stage) an estimate of the answer and an estimate of the likely error of this estimated answer
(gotten by comparing the new answer with the old answer, for example), and so can compute an estimated
relative error (est abs err/est answer) which the code checks against the requested relative error goal supplied
by the parameter epsrel.
We are assuming that the defaults are being used, and hence epsabs has the value 0.0, so that the convergence
criterion used by the code is
est rel err epsrel
(8.3)
or
(8.4)
(8.5)
or
21
We can check that the values returned by quad_qags are at least consistent with the advertised convergence
criterion.
(%i13) est_answer : first(qlist);
(%o13)
0.444444
(%i14) est_abs_err : second(qlist);
(%o14)
4.93432455E-16
(%i15) est_rel_err : est_abs_err/est_answer;
(%o15)
1.11022302E-15
display2d:false$
limit(log(sin(x)),x,0,plus);
minf
ix : taylor(log(sin(x)),x,0,2);
+log(x)-x2/6
int_ix:integrate(ix,x);
x*log(x)-x3/18-x
limit(int_ix,x,0,plus);
0
assume(eps>0,eps<1)$
integrate(ix,x,0,eps);
(18*eps*log(eps)-eps3-18*eps)/18
expand(%);
eps*log(eps)-eps3/18-eps
limit(eps*log(eps),eps,0,plus);
0
Output %o2 indicates that the integrand as x 0+ . To see if this is an integrable singularity, we
examine the integrand for x positive but close to 0, using a Taylor series expansion. We let eps represent , a
small positive number to be used as the upper limit of a small integration interval.
The approximate integrand, ix, shows a logarithmic singularity at x = 0. The indefinite integral of the approximate integrand, int ix, is finite as x 0+ . And finally, the integral of the approximate integrand over (0, ) is
finite. Hence we are dealing with an integrable singularity, and we use quad_qags to evaluate the numerical
value of the exact integrand over [0, 1].
(%i10) quad_qags(log(sin(x)),x,0,1);
(%o10) [-1.056720205991585,1.1731951032784962E-15,231,0]
22
Use of integrate with this integrand-domain returns an expression involving the dilogarithm function
li[2](z) in which z is a complex number. At present, Maxima cannot find numerical values of the dilogarithm function for non-real arguments.
(%i11)
(%o11)
(%i12)
(%o12)
(%i13)
(%o13)
float(li[2](1));
1.644934066848226
float(li[2](1+%i));
li[2](%i+1.0)
integrate(log(sin(x)),x,0,1);
-%i*atan(sin(1)/(cos(1)+1))-%i*atan(sin(1)/(cos(1)-1))+log(sin(1))
-log(2*cos(1)+2)/2-log(2-2*cos(1))/2
+%i*li[2](%e%i)+%i*li[2](-%e%i)
-%i*%pi2/12+%i/2
v1(u)
u2
v2(u)
f (u, v) dv
u1
du
(8.6)
v1(u)
(fpprintprec:8,display2d:false)$
g : x*y/(x+y)$
tval : (block [fpprec:20],bfloat (integrate (integrate (g,y,0,x/2),x,1,3) ));
positive, negative, or zero?
8.1930239b-1
(8.7)
23
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
Bear in mind that the quadpack functions (at present) have, at most, 16 digit accuracy. For a difficult numerical
integral, the accuracy can be much less than that.
Example 2
For our second example, we consider the double integral
Z 1 Z 2+x
xy2
e
dy dx
0
(8.8)
(%i7) g : exp(x-y2)$
(%i8) tval : block([fpprec:20],bfloat(integrate( integrate(g,y,1,2+x),x,0,1)));
(%o8) 2.3846836b-1
(%i9) quad_qags( quad_qags(g,y,1,2+x)[1],x,0,1);
(%o9) [0.238468,2.64753066E-15,21,0]
(%i10) block([fpprec:20],bfloat(abs (%[1] - tval)));
(%o10) 4.229659b-18
(%i11) %/tval;
(%o11) 1.7736772b-17
The Maxima coordinator, Robert Dodier has warned about the lack of accuracy diagnostics with the inner
integral done by quad qags:
A nested numerical integral like this has a couple of drawbacks, whatever the method. (1) The
estimated error in the inner integral isnt taken into account in the error estimate for the outer.
(2) Methods specifically devised for multi-dimensional integrals are typically more efficient than
repeated 1-d integrals.
8.5.6
The function quad_qag is useful primarily due to its ability to deal with functions with some general oscillatory behavior.
The key feature to watch out for is the required fifth slot argument which the manual calls key. This slot
can have any integral value between 1 and 6 inclusive, with the higher values corresponding to higer order
Gauss-Kronrod integration rules for more complicated oscillatory behavior.
Use the syntax:
quad_qag( expr, var, a, b, key, [epsrel, epsabs, limit] )
R1
24
Example 1
Since the main feature of quad_qag is the ability to select a high order quadrature method for a generally
oscillating
comparing quad_qag with quad_qags for such a case. We consider the
R 1 integrand, we begin by
x
integral 0 cos(50 x) sin(3 x) e dx.
(%i1)
(%i2)
(%i3)
(%o3)
(%i4)
(%i5)
(fpprintprec:8,display2d:false)$
f : cos(50*x)*sin(3*x)*exp(-x)$
tval : block ([fpprec:20],bfloat( integrate (f,x,0,1) ));
-1.9145466b-3
(load(draw),load(qdraw))$
qdraw( ex(f,x,0,1) )$
0.2
0.4
0.6
0.8
We see that both methods returned results with about the same relative error, but that quad_qag needed only
about one fifth the number of integrand evaluations as compared with quad_qags. This extra efficiency of
quad_qag for this type of integrand may be of interest in certain kinds of intensive numerical work. Naturally,
the number of integrand evaluations needed does not necessarily translate simply into time saved, so timing
trials would be appropriate when considering this option.
25
Example 2
R1
We compare quad_qag and quad_qags with the numerical evaluation of the integral 0 ex dx, which
has neither special oscillatory behavior (which quad_qag might help with) nor singular behavior (which
quad_qags might help with).
(%i12)
(%o12)
(%i13)
(%o13)
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
(%i17)
(%o17)
(%i18)
(%o18)
We see that using quad_qags for this function results in slightly smaller relative error while using only two
thirds the number of integrand evaluations compared with quad_qag.
Example 3
We compare quad_qag and quad_qags with the numerical evaluation of the integral
which has quasi-singular behavior at x = 0. See Sec.(8.5.4) for a plot of this integrand.
(%i19)
(%i20)
(%o20)
(%i21)
(%o21)
(%i22)
(%o22)
(%i23)
(%o23)
(%i24)
(%o24)
(%i25)
(%o25)
(%i26)
(%o26)
R1
0
x ln(x) dx,
f : sqrt(x)*log(1/x)$
tval : block ([fpprec:20], bfloat( integrate (f,x,0,1) ));
4.4444444b-1
quad_qag(f,x,0,1,3);
[0.444444,3.17009685E-9,961,0]
block ([fpprec:20], bfloat(abs(first(%) - tval)));
4.7663293b-12
%/tval;
1.072424b-11
quad_qags(f,x,0,1);
[0.444444,4.93432455E-16,315,0]
block ([fpprec:20], bfloat(abs(first(%) - tval)));
8.0182679b-17
%/tval;
1.8041102b-16
We see that using quad_qags for this function (which has a quasi-singular behavior near x = 0 ) returns
a much smaller relative error while using only one third the number of integrand evaluations compared with
quad_qag.
You can use quad_qag for numerical double integrals, following the pattern we used with qaud_qags, and
you can use different methods for each of the two axes.
26
8.5.7 quad qagi for a Non-finite Interval
See Sec.(8.8) for a decision tree for quadrature over a non-finite interval.
The syntax is
quad_qagi ( expr, var, a, b, [epsrel, epsabs, limit] ), where
(a,b) are the limits of integration.
Thus you will have (omitting the optional args):
quad_qagi (expr, var, minf, b ) with b finite,
quad_qagi ( expr, var, a, inf ), with a finite, or
quad_qagi (expr, var, minf, inf ).
If at least one of (a,b) are not equal to (minf,inf), a noun form will be returned.
The Maxima function quad_qagi returns the same type of information (approx-integral, est-abs-error, nfe,
error-code) in a list that quad_qags returns, and the possible error codes returned have the same meaning.
Here we test the syntax and behavior with a simple integrand, first over [0, ]:
(%i1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
(fpprintprec:8,display2d:false)$
tval : block ([fpprec:20],bfloat( integrate (exp(-x2),x,0,inf) ));
8.8622692b-1
quad_qagi(exp(-x2),x,0,inf);
[0.886227,7.10131839E-9,135,0]
block ([fpprec:20], bfloat(abs(first(%) - tval)));
7.2688979b-17
%/tval;
8.202073b-17
quad_qagi(exp(-x2),x,minf,0);
[0.886227,7.10131839E-9,135,0]
block ([fpprec:20], bfloat(abs(first(%) - tval)));
7.2688979b-17
27
Example 1
Here is another simple example:
(%i11)
(%i12)
(%o12)
(%i13)
(%o13)
(%i14)
(%o14)
(%i15)
(%o15)
g : exp(-x)*x(5/100)$
tval : block ([fpprec:20],bfloat( integrate(g,x,0,inf) ));
9.7350426b-1
quad_qagi(g,x,0,inf);
[0.973504,1.2270015E-9,315,0]
block ([fpprec:20], bfloat(abs(first(%) - tval)));
7.9340695b-15
%/tval;
8.15001b-15
We see that the use of the default mode (accepting the default epsrel:1d-8 and epsabs:0 ) has resulted in an
absolute error which is close to the floating point limit and a relative error of the same order of magnitude
(because the value of the integral is of order 1).
Example 2
R
We evaluate the integral 0 ex ln(x) dx = , where is the Euler-Mascheroni constant, 0.5772156649015329.
Maxima has this constant available as %gamma, although you need to use either float or bfloat to get the numerical value.
(%i16)
(%i17)
(%o17)
(%i18)
(%o18)
(%i19)
(%o19)
(%i20)
(%o20)
g : exp(-x)*log(x)$
tval : block ([fpprec:20],bfloat( integrate(g,x,0,inf) ));
-5.7721566b-1
quad_qagi(g,x,0,inf);
[-0.577216,5.11052578E-9,345,0]
block ([fpprec:20], bfloat(abs(first(%) - tval)));
2.6595919b-15
%/tval;
-4.6076226b-15
Example 3
A symmetrical version of a Fourier transform pair is defined by the equations
Z
1
G(k) ei k x dk
g(x) =
2
Z
1
G(k) =
g(x) ei k x dx
2
(8.9)
(8.10)
2
An example of such
transform pair which respects this symmetrical definition is: if g(x) = a eb x ,
a Fourier
2
then G(k) = (a/ 2 b) ek /(4 b) .
(%i21)
(%i22)
(%i23)
(%o23)
assume(a>0,b>0,k>0)$
g :a*exp(-b*x2)$
gft:integrate(exp(-%i*k*x)*g,x,minf,inf)/sqrt(2*%pi);
a*%e-(k2/(4*b))/(sqrt(2)*sqrt(b))
28
To check this relation with quag_qagi, lets define f to be g for the case a, b and k are all set equal to 1.
(%i24)
(%o24)
(%i25)
(%o25)
(%i26)
(%o26)
f : subst([a=1,b=1,k=1],g);
%e-x2
fft : subst([a=1,b=1,k=1],gft);
%e-(1/4)/sqrt(2)
float(fft);
0.550695
If we try to submit an explicitly complex integrand to quad_qagi we get a noun form back, indicating failure.
(A similar result occurs with any quadpack function.).
(%i27) quad_qagi(f*exp(-%i*x),x,minf,inf);
(%o27) quad_qagi(%e(-x2-%i*x),x,minf,inf,epsrel = 1.0E-8,epsabs = 0.0,limit
= 200)
You can use quad_qagi for numerical double integrals, following the pattern we used for quad_qags, and
you can choose different methods for each of the axes.
8.6
There are specialised Quadpack routines for particular kinds of one dimensional integrals. See Sec.(8.7) for a
decision tree for a finite region numerical integral using the Quadpack functions.
8.6.1 quad qagp for Internal Integrand Singularities
The quadpack function quad_qagp is both more efficient and more accurate than quad_qags for the case
of integrand singularities interior to the integration interval. The syntax is the same as quad_qags, except
that the fifth argument should be a list of either one or more points where the interior singularities occur. The
elements of the points list should evaluate to numbers.
We compare the use of quad_qagp and quad_qags for the numerical value of the integral
Z 3
x3 ln x2 1 x2 2 dx
(8.11)
2.
quad_qagp(x3*log(abs((x2-1)*(x2-2))),x,0,3,[1,sqrt(2)]);
[52.740748,2.62476263E-7,1029,0]
quad_qags(x3*log(abs((x2-1)*(x2-2))),x,0,3);
[52.740748,4.08844336E-7,1869,0]
29
For the integral
R2
2
R2
For the integral 2 (x + x4 ) sin(5 x) dx (default options), use quad_qawo(x + x4, x, -2, 2, 5, sin).
R2
Here we compare quad_qawo with quad_qags for the integral 2 (x + x4 ) cos(3 x) dx.
(%i1)
(%i2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
(%o8)
(%i9)
(%o9)
fpprintprec:8$
g : (x+x4)*cos(3*x)$
tval : bfloat( integrate(g,x,-2,2) ),fpprec:20;
3.6477501b0
quad_qawo(x+x4,x,-2,2,3,cos);
[3.6477502, 0.0, 25, 0]
abs(first(%) - tval),fpprec:20;
4.0522056b-18
%/tval,fpprec:20;
1.110878b-18
quad_qags(g,x,-2,2);
[3.6477502, 8.89609255E-14, 63, 0]
abs(first(%) - tval),fpprec:20;
1.7723046b-15
%/tval,fpprec:20;
4.8586239b-16
We see that quad_qawo finds the numerical value with zero relative error as compared with a non-zero
relative error using quad_qags, and with many less integrand evaluations.
8.6.3 quad qaws for End Point Algebraic and Logarithmic Singularities
The syntax is:
quad_qaws (f(x), x, a, b, alpha, beta, wfun,[epsrel, epsabs, limit])
Rb
This Maxima function is designed for the efficient evaluation of integrals of the form a f (x) w(x) dx in which
the appropriate singular end point weight function is chosen from among different versions via the three parameters wfun, (represented by alpha), and (represented by beta).
The most general case in which one has both algebraic and logarithmic singularities of the integrand at both
end points corresponds to 6= 0 and 6= 0 and
w(x) = (x a) (b x) ln(x a) ln(b x)
(8.12)
The parameters and govern the degree of algebraic singularity at the end points. One needs both > 1
and > 1 for convergence of the integrals.
In particular, one can choose = 0 and/or = 0 to handle an algebraic singularity at only one end of the
interval or no algebraic singularities at all.
The parameter wfun determines the existence and location of possible end point logarithmic singularities of
the integrand.
wfun
1
2
3
4
w(x)
(x a) (b x)
(x a) (b x) ln(x a)
(x a) (b x) ln(b x)
(x a) (b x) ln(x a) ln(b x)
30
Example 1: Pure Logarithmic Singularities
For the case that =R0 and = 0, there are no end point algebraic singularities, only logarithmic singularities.
1
A simple example is 0 ln(x) dx, which corresponds to wfun = 2:
(%i1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
fpprintprec:8$
tval : bfloat( integrate(log(x),x,0,1) ),fpprec:20;
- 1.0b0
quad_qaws(1,x,0,1,0,0,2);
[- 1.0, 9.68809031E-15, 40, 0]
abs(first(%) - tval),fpprec:20;
0.0b0
quad_qags(log(x),x,0,1);
[- 1.0, 1.11022302E-15, 231, 0]
abs(first(%) - tval),fpprec:20;
0.0b0
which illustrates the efficiency of quad_qaws compared to quad_qags for this type of integrand.
Example 2: Pure Algebraic Singularity
The case wfun = 1 corresponds to purely algebraic end point singularities.
Here we compare quad_qaws with quad_qags for the evaluation of the integral
an exact symbolic answer in terms of erf(z) for this integral from integrate.
R1
0
sin(x)
(%i7) expand(bfloat(integrate(sin(x)/sqrt(x),x,0,1))),fpprec:20;
(%o7)
1.717976b0 cos(0.25 %pi) - 8.404048b-1 sin(0.25 %pi)
(%i8) tval : bfloat(%),fpprec:20;
(%o8)
6.205366b-1
(%i9) quad_qaws(sin(x),x,0,1,-1/2,0,1);
(%o9)
[0.620537, 4.31887834E-15, 40, 0]
(%i10) abs(first(%) - tval),fpprec:20;
(%o10)
8.8091426b-19
(%i11) %/tval,fpprec:20;
(%o11)
1.4196008b-18
(%i12) quad_qags(sin(x)/sqrt(x),x,0,1);
(%o12)
[0.620537, 3.48387985E-13, 231, 0]
(%i13) abs(first(%) - tval),fpprec:20;
(%o13)
1.1014138b-16
(%i14) %/tval,fpprec:20;
(%o14)
1.7749378b-16
We see that quad_qaws uses about one sixth the number of function evaluations (as compared with quad_qags)
and returns a much more accurate answer.
Example 3: Both Algebraic and Logarithmic Singularity at an End Point
R1
+
x ln(x) 0 as x 0 .
(%i1) fpprintprec:8$
(%i2) limit(log(x)/sqrt(x),x,0,plus);
(%o2)
minf
31
(%i3) integrate(log(x)/sqrt(x),x);
(%o3)
2 (sqrt(x) log(x) - 2 sqrt(x))
(%i4) limit(%,x,0,plus);
(%o4)
0
(%i5) tval : bfloat( integrate(log(x)/sqrt(x),x,0,1)),fpprec:20;
(%o5)
- 4.0b0
(%i6) quad_qaws(1,x,0,1,-1/2,0,2);
(%o6)
[- 4.0, 3.59396672E-13, 40, 0]
(%i7) abs(first(%) - tval),fpprec:20;
(%o7)
0.0b0
(%i8) quad_qags(log(x)/sqrt(x),x,0,1);
(%o8)
[- 4.0, 1.94066985E-13, 315, 0]
(%i9) abs(first(%) - tval),fpprec:20;
(%o9)
2.6645352b-15
(%i10) %/tval,fpprec:20;
(%o10)
- 6.6613381b-16
Again we see the relative efficiency and accuracy of quad_qaws for this type of integral.
8.6.4 quad qawc for a Cauchy Principal Value Integral
This function has the syntax:
quad_qawc (f(x), x, c, a, b,[epsrel, epsabs, limit]).
The actual integrand is g(x) = f (x)/(x c), with dependent variable x, to be integrated over the interval [a, b]
and you need to pick out f (x) by hand here. In using quad_qawc, the argument c is placed between the name
of the variable of integration (here x) and the lower limit of integration.
An integral with a pole on the contour does not exist in the strict sense, but if g(x) has a simple pole on the
real axis at x = c, one defines the Cauchy principal value as the symmetrical limit (with a < c < b)
Z c
Z b
Z b
g(x) dx +
g(x) dx
(8.13)
P
g(x) dx = lim+
a
c+
Z b
Z b
f (x)
f (x)
f (x)
P
dx = lim+
dx +
dx
0
xc
a xc
a
c+ x c
(8.14)
We can find the default values of the optional method parameters of quad_qawc by including an undefined
symbol in our call:
(%i11) quad_qawc(1/(x2-1),x,1,0,b);
1
(%o11) quad_qawc(------, x, 1, 0, b, epsrel = 1.0E-8, epsabs = 0.0, limit = 200)
2
x - 1
We see that the default settings cause the algorithm to look at the relative error of succeeding approximations
to the numerical answer.
32
As a simple example of the syntax we consider the principal value integral
Z 2
Z 2
1
1
P
dx = P
dx = ln(3)/2
2
0 x 1
0 (x 1) (x + 1)
(8.15)
We use assume to prep integrate and then implement the basic definition provided by Eq. (8.13)
(%i1) fpprintprec:8$
(%i2) assume(eps>0, eps<1)$
(%i3) integrate(1/(x2-1),x,0,1-eps) +
integrate(1/(x2-1),x,1+eps,2);
log(eps + 2)
log(2 - eps)
log(3)
(%o3)
------------ - ------------ - -----2
2
2
(%i4) limit(%,eps,0,plus);
log(3)
(%o4)
- -----2
(%i5) tval : bfloat(%),fpprec:20;
(%o5)
- 5.4930614b-1
We now compare the result returned by integrate with the numerical value returned by quad_qawc, noting
that f (x) = 1/(1 + x).
(%i6) quad_qawc(1/(1+x),x,1,0,2);
(%o6)
[- 0.549306, 1.51336373E-11, 105, 0]
(%i7) abs(first(%) - tval),fpprec:20;
(%o7)
6.5665382b-17
(%i8) %/tval,fpprec:20;
(%o8)
- 1.1954241b-16
We see that the relative error of the returned answer is much less than the (default) requested minimum relative
error.
If we run quad_qawc requesting that convergence be based on absolute error instead of relative error,
(%i9) quad_qawc(1/(1+x),x,1,0,2,epsabs=1.0e-10,epsrel=0.0);
(%o9)
[- 0.549306, 1.51336373E-11, 105, 0]
(%i10) abs(first(%) - tval),fpprec:20;
(%o10)
6.5665382b-17
(%i11) %/tval,fpprec:20;
(%o11)
- 1.1954241b-16
we see no significant difference in the returned accuracy, and again we see that the absolute error of the returned
answer is much less than the requested minimum absolute error.
33
8.6.5 quad qawf for a Semi-Infinite Range Cosine or Sine Fourier Transform
The function quad_qawf calculates a Fourier cosine or Fourier sine transform (up to an overall normalization
factor) on the semi-infinite interval [a, ]. If we let w stand for the angular frequency in radians, the integrand
is f(x)*cos(w*x) if the trig parameter is cos, and the integrand is f(x)*sin(w*x) if the trig parameter is sin.
The calling syntax is
quad_qawf (f(x), x, a, w, trig, [epsabs, limit, maxp1, limlst])
Thus quad_qawf (f(x), x, 0, w, cos) will find a numerical approximation to the integral
Z
f (x) cos(w x) dx
(8.16)
If we call quad_qawf with undefined parameter(s), we get a look at the default values of the optional method
parameters:
(%i12) quad_qawf(exp(-a*x),x,0,w,cos);
- a x
(%o12) quad_qawf(%e
, x, 0, w, cos, epsabs = 1.0E-10, limit = 200,
maxp1 = 100, limlst = 10)
The manual does not define the meaning of cycles. There is no epsrel parameter used for this function.
Here is the manual example, organised in our way. In this example w = 1 and a = 0.
(%i1) fpprintprec:8$
(%i2) integrate (exp(-x2)*cos(x), x, 0, inf);
- 1/4
%e
sqrt(%pi)
(%o2)
----------------2
(%i3) tval : bfloat(%),fpprec:20;
(%o3)
6.9019422b-1
(%i4) quad_qawf (exp(-x2), x, 0, 1, cos );
(%o4)
[0.690194, 2.84846299E-11, 215, 0]
(%i5) abs(first(%) - tval),fpprec:20;
(%o5)
3.909904b-17
(%i6) %/tval,fpprec:20;
(%o6)
5.664933b-17
We see that the absolute error of the returned answer is much less than the (default) requested minimum absolute
error.
34
8.7
If your definite integral is over a finite region of integration [a, b], then
1. If the integrand has the form w(x)*f(x), where f(x) is a smooth function over the region of integration,
then
If w(x) has the form of either cos( c*x ) or sin( c*x ), where c is a constant, use quad_qawo.
Else if the factor w(x) has the form (note the limits of integration are [ a, b ]
(x - a)ae * (b - x)be * (log(x - a))na * (log(b - x))nb
where na, nb have the values 0 or 1, and both ae and be are greater than 1, then use quad_qaws.
(This is a case where we need a routine which is designed to handle end point singularities.)
Else if the factor w(x) is 1/(x - c) for some constant c with a < c < b, then use quad_qawc, the
Cauchy principle value routine.
2. Otherwise, if you do not care too much about possible inefficient use of computer time, and do not want
to further analyze the problem, use quad_qags.
3. Otherwise, if the integrand is smooth, use quad_qag.
4. Otherwise, if there are discontinuities or singularities of the integrand or of the derivative of the integrand, and you know where they are, split the integration range at these points and separately integrate
over each subinterval.
5. Otherwise, if the integrand has end point singularities, use quad_qags.
6. Otherwise, if the integrand has an oscillatory behavior of nonspecific type, and no singularities, use
quad_qag with the fifth key slot containing the value 6.
7. Otherwise, use quad_qags.
35
B.
C.
D.
E.
F.
G.
Preface
COPYING AND DISTRIBUTION POLICY
This document is part of a series of notes titled
"Maxima by Example" and is made available
via the authors webpage http://www.csulb.edu/woollett/
to aid new users of the Maxima computer algebra system.
NON-PROFIT PRINTING AND DISTRIBUTION IS PERMITTED.
You may make copies of this document and distribute them
to others as long as you charge no more than the costs of printing.
These notes (with some modifications) will be published in book form
eventually via Lulu.com in an arrangement which will continue
to allow unlimited free download of the pdf files as well as the option
of ordering a low cost paperbound version of these notes.
Feedback from readers is the best way for this series of notes to become more helpful to new users of Maxima.
All comments and suggestions for improvements will be appreciated and carefully considered.
LOADING FILES
The defaults allow you to use the brief version load(brmbrg) to load in the
Maxima file brmbrg.lisp.
To load in your own file, such as qbromberg.mac (used in this chapter),
using the brief version load(qbromberg), you either need to place
qbromberg.mac in one of the folders Maxima searches by default, or
else put a line like:
file_search_maxima : append(["c:/work3/###.{mac,mc}"],file_search_maxima )$
in your personal startup file maxima-init.mac (see Ch. 1, Introduction to Maxima
for more information about this).
Otherwise you need to provide a complete path in double quotes,
as in load("c:/work3/qbromberg.mac"),
We always use the brief load version in our examples, which are generated
using the Xmaxima graphics interface on a Windows XP computer, and copied
into a fancy verbatim environment in a latex file which uses the fancyvrb
and color packages.
We use qdraw.mac for plots (see Ch.5), which uses draw2d defined
in share/draw/draw.lisp.
Maxima, a Computer Algebra System.
Some numerical results depend on the Lisp version used.
This chapter uses Version 5.18.1 (2009) using Lisp GNU
Common Lisp (GCL) GCL 2.6.8 (aka GCL).
http://maxima.sourceforge.net/
9.1 Introduction
This chapter is divided into two sections.
In the first section we discuss the use of bfloat, including examples which also involve fpprec, bfloatp,
bfallroots, fpprintprec, print, and printf. The second section of Chapter 9 presents examples of
the use of Maxima for arbitrary precision quadrature (numerical integration). (In Chapter 8, we gave numerous
examples of numerical integration using the Quadpack functions such as quad_qags as well as romberg.
Those examples all accepted the default floating point precision of Maxima).
Chapter 10 covers both Fourier transform and Laplace transform type integrals. Chapter 11 presents tools for
the use of fast Fourier transforms with examples of use.
Software files developed for Ch. 9 and available on the authors web page include:
1. fdf.mac, 2. qbromberg.mac. ,
3. quad_de.mac, 4. quad_ts.mac, 5. quad_gs.mac.
9.2
fpprec;
16
?fpprec;
56
:lisp $fpprec
:lisp fpprec
We discuss some effects of the fact that computer arithmetic is carried out with binary bit representation of
decimal numbers in Sec. 9.2.5.
4
Controlling Printed Digits with fpprintprec
When using bigfloat numbers, the screen can quickly fill up with numbers with many digits, and fpprintprec
allows you to control how many digits are displayed. For bigfloat numbers, when fpprintprec has a value between 2 and fpprec (inclusive), the number of digits printed is equal to fpprintprec. Otherwise, fpprintprec
can be 0, or greater than fpprec, in which case the number of digits printed is equal to fpprec. fpprintprec
cannot be 1. The setting of fpprintprec does not affect the precision of the bigfloat arithmetic carried out, only
the setting of fpprec matters.
The parameter fpprec can be used as a local variable in a function defined using block, and set to a local
value which does not affect the global setting. Such a locally defined value of fpprec governs the bigfloat
calculations in that function and in any functions called by that function, and in any third layer functions
called by the secondary layer functions, etc. fpprintprec can be set to a value inside a function defined with
block,without changing the global value, provided you include the name fpprintprec in the local variables
bracket [ ]:
(%i1) [fpprec,fpprintprec];
(%o1)
[16, 0]
(%i2) piby2 : block([fpprintprec,fpprec:30,val],
val:bfloat(%pi/2),
fpprintprec:8,
disp(val),
print(" ",val),
val);
1.5707963b0
1.5707963b0
(%o2)
1.57079632679489661923132169164b0
(%i3) [fpprec,fpprintprec];
(%o3)
[16, 0]
For simple bfloat uses in interactive mode, one can use the syntax bfloat-job, fpprec:fp ; which implicitly
uses the ev(...) construct with temporary settings of global flags as in
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
(%o8)
bfloat(%pi),fpprec:20;
3.1415926535897932385b0
slength(string(%));
23
fpprec;
16
bfloat(%pi),fpprec:40;
3.141592653589793238462643383279502884197b0
slength(string(%));
43
fpprec;
16
tval : bfloat(integrate(exp(x),x,-1,1)),fpprec:30;
2.35040238728760291376476370119b0
slength(string(%));
33
5
Next we illustrate passing both a bigfloat number as well as local values of fpprec and fpprintprec to a second
function. Function f1 is designed to call function f2:
(%i1) f2(w) := block([v2 ],
disp(" in f2 "),
display([w,fpprec,fpprintprec]),
v2 : sin(w),
display(v2),
print(" "),
v2 )$
(%i2) f1(x,fp,fprt) :=
block([fpprintprec,fpprec:fp,v1],
fpprintprec:fprt,
disp(" in f1 "),
display([x,fpprec,fpprintprec]),
v1 : f2(bfloat(x))2,
print(" in f1, v1 = ",v1),
v1 )$
We see that the called function (f2) maintains the values of fpprec and fpprintprec which exist in the
calling function (f1).
Bigfloat numbers are contagious in the sense that, for example, multiplying (or adding) an integer or ordinary
float number with a bigfloat results in a bigfloat number. In the above example sin(w) is a bigfloat since w is
one.
(%i5) 1 + 2.0b0;
(%o5)
(%i6) 1.0 + 2.0b0;
(%o6)
(%i7) sin(0.5b0);
(%o7)
3.0b0
3.0b0
4.79425538604203b-1
The Maxima symbol %pi is not automatically converted by contagion (in the present version of Maxima), and
an extra use of bfloat does the conversion.
(%i8) a:2.38b-1$
(%i9) exp(%pi*a);
(%o9)
(%i10) bfloat(%);
(%o10)
2.38b-1 %pi
%e
2.112134508503361b0
6
A recent comment by Maxima developer Volker van Nek on the Maxima mailing list illustrates how the setting
of fpprec can affect what is printed to the screen when doing bigfloat arithmetic.
(%i11) 1b0 + 1b-25,fpprec:26;
(%o11)
1.0000000000000000000000001b0
(%i12) slength(string(%));
(%o12)
29
Note that 1b-25 is the bigfloat version of 1025 . In the case above the value of fpprec is large enough to see the
effect of the bigfloat addition. The number of digits identified by the conversion of the number to a string and
then finding the length of the string is 29 3 = 26 since the three string characters [., b, 0] do not contribute
to the precision of the number. If we leave the fpprec at 26 and add to 1 the bigfloat equivalent of 1026 ,
Maxima prints out a bigfloat version of 1, but if we subtract from that answer 1b0 we do not get zero:
(%i13)
(%o13)
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
(%i17)
(%o17)
1b0 + 1b-25,fpprec:26;
1.0000000000000000000000001b0
slength(string(%));
29
1b0 +10b0(-26),fpprec:26;
1.0b0
% - 1b0,fpprec:26;
9.6935228033557930648993206b-27
slength(string(%));
31
Of the thirty one characters present in this string, the five characters [., b, , 2, 7] do not contribute to the precision, , leaving 26 digits of precision. Note that the setting of fpprintprec was 0 in the above, which provides
for printing of the same number of significant digits as the value of fpprec.
Here are three ways to enter the bigfloat equivalent of 1/10 = 101 = 0.1:
(%i18) [1b-1,bfloat(10(-1)),10b0(-1)];
(%o18)
[1.0b-1, 1.0b-1, 1.0b-1]
We next show that once bigfloat numbers are in play inside a block function in which a local value of fpprec
is set, the subsequent arithmetic is the same whether or not you wrap each operation with bfloat.
(%i19) test1(h,j,fp):=
block([fpprec:fp,u,a,x,w],
u:bfloat(h*j),
a:bfloat(exp(-u)),
x:bfloat(exp(u-a)),
w:bfloat(exp(-a)+x),
[x,w])$
(%i20) test2(h,j,fp):=
block([fpprec:fp,u,a,x,w],
u:bfloat(h*j),
a:exp(-u),
x:exp(u-a),
w:exp(-a)+x,
[x,w])$
(%i21) [xt,wt]:test1(1/16,9,60)$
(%i22) [x1,w1]:test1(1/16,9,40)$
(%i23) [x2,w2]:test2(1/16,9,40)$
(%i24) [x1,w1]-[xt,wt],fpprec:60;
(%o24) [- 2.29699398191727953386796229322249912456243487302509210328785b-42,
- 9.07907621847706474924315736438559811433348894389391230442376b-42]
(%i25) [x2,w2]-[xt,wt],fpprec:60;
(%o25) [- 2.29699398191727953386796229322249912456243487302509210328785b-42,
- 9.07907621847706474924315736438559811433348894389391230442376b-42]
(%i26) bfloat([x1,w1]-[xt,wt]),fpprec:60;
(%o26) [- 2.29699398191727953386796229322249912456243487302509210328785b-42,
- 9.07907621847706474924315736438559811433348894389391230442376b-42]
(%i27) map(bfloatp,%o5);
(%o27)
[true, true]
(%i28) map(bfloatp,%o4);
(%o28)
[true, true]
In the above, we used the completely bfloat wrapped version test1(..) to define answers with 60 digit precision, and then used test1(..) and test2(..) to compute comparison answers at 40 digit precision. We see that
there is no difference in precision between the answers returned by the two test versions (each using 40 digit
precision).
We also see, from the output %08, that arith_job, fpprec:60; using interactive mode produces the
same answer (with bigfloats already in play) whether or not the arithmetic_job is wrapped in bfloat.
The numbers returned by both test versions are bigfloats, as indicated by the last two outputs.
9.2.2 Using print and printf with Bigfloats
In Sec. 9.2.1 we described the relations between the settings of fpprec and fpprintprec. Once you have
generated a bigfloat with some precision, it is convenient to be able to control how many digits are displayed.
We start with the use of print. If you start with the global default value of 16 for fpprec and the default
value of 0 for fpprintprec, you can use a simple one line command for a low number of digits, as shown in the
following. We first define a bigfloat bf1 to have fpprec = 45 digits of precision:
(%i1) [fpprec,fpprintprec];
(%o1)
[16, 0]
(%i2) bf1:bfloat(integrate(exp(x),x,-1,1)),fpprec:45;
(%o2)
2.35040238728760291376476370119120163031143596b0
(%i3) slength(string(%));
(%o3)
48
We then use print with fpprintprec to get increasing numbers of digits on the screen:
(%i4) print(bf1),fpprintprec:12$
2.35040238728b0
(%i5) [fpprec,fpprintprec];
(%o5)
[16, 0]
(%i6) print(bf1),fpprintprec:15$
2.3504023872876b0
(%i7) [fpprec,fpprintprec];
(%o7)
[16, 0]
(%i8) print(bf1),fpprintprec:16$
2.35040238728760291376476370119120163031143596b0
(%i9) [fpprec,fpprintprec];
(%o9)
[16, 0]
(%i10) slength(string(%o8));
(%o10)
48
8
As you see above, when fpprintprec reaches the global value of fpprec = 16 all 45 digits are printed. To
control the number of printed digits, you need to locally set the value of fpprec as shown here:
(%i11) print(bf1),fpprec:20,fpprintprec:18$
2.35040238728760291b0
The format string is enclosed in double quotes, with d used for an integer, f used for a floating point number,
a used for a Maxima string, e used for exponential display of a floating point number, and h used for a
bigfloat number. You can include the newline instruction with % anywhere and as many times as you wish.
In the example above, we used the string formatting to display the bigfloat number bf, which required that bf be
converting to a Maxima string using string. Because we did not include any spaces between the integer format
instruction d and the string format character a, we get 32.0... instead of 3 2.0....
(%i4) printf(true," da",3,string(bf))$
32.06115362243855782796594038016b-9
(%i5) printf(true," d
a",3,string(bf))$
3
2.06115362243855782796594038016b-9
(%i6) (printf(true," d
a",3,string(bf)),
printf(true," d
a",3,string(bf)))$
3
2.06115362243855782796594038016b-9 3
2.06115362243855782796594038016b-9
(%i7) (printf(true," d
a%",3,string(bf)),
printf(true," d
a",3,string(bf)))$
3
2.06115362243855782796594038016b-9
3
2.06115362243855782796594038016b-9
To get the output on successive lines we had to include the newline instruction %. To control the number of
significant figures displayed, we use fpprintprec:
(%i8) fpprintprec:8$
(%i9) printf(true," d
3
2.0611536b-9
a",3,string(bf))$
printf(true," d
f",3,bf)$
0.0000000020611536224385579
printf(true," d
e",3,bf)$
2.0611536224385579E-9
printf(true," d
h",3,bf)$
0.0000000020611536
value
1
2
3
4
2.7182818b0
5.459815b1
8.1030839b3
8.8861105b6
Note the crucial use of the newline instruction % to get the table output. Some general use examples of printf
can be found in the Maxima manual and in the file
C:\Program Files\Maxima-5.17.1\share\maxima\5.17.1\share\
contrib\stringproc\rtestprintf.mac
10
We can use printf for the titles and empty lines with the alternative version. We first define an alternative
function print_test2:
(%i3) print_test2(fp) :=
block([fpprec,fpprintprec,val],
fpprec : fp,
fpprintprec : 8,
display(fpprec),
printf(true,"% a
a %%",k,value),
for k thru 4 do
( val : bfloat(exp(k2)),
printf(true," d
a %",k,string(val) ) ))$
value
1
2
3
4
2.7182818b0
5.459815b1
8.1030839b3
8.8861105b6
fpprintprec:8$
pi50 : bfloat(%pi),fpprec:50;
3.1415926b0
pi30 : bfloat(%pi),fpprec:30;
3.1415926b0
abs(pi30 - pi50),fpprec:60;
1.6956855b-31
twopi : bfloat(2*%pi),fpprec:60;
6.2831853b0
pisum40 : pi30 + pi50,fpprec:40;
6.2831853b0
abs(pisum40 - twopi),fpprec:60;
1.6956855b-31
pisum60 : pi30 + pi50,fpprec:60;
6.2831853b0
abs(pisum60 - twopi),fpprec:60;
1.6956855b-31
11
9.2.4 Polynomial Roots Using bfallroots
The Maxima function bfallroots has the same syntax as allroots, and computes numerical approximations of the real and complex roots of a polynomial or polynomial expression of one variable. In all respects,
bfallroots is identical to allroots except that bfallroots computes the roots using bigfloats, and
to take advantage of bigfloats you need to set both ffprec and ratepsilon to compatible values (as our example
shows). The source code of bfallroots with some comments is in the file cpoly.lisp in the src directory.
Our example is a cubic equation whose three degenerate roots are simply . We are using Maxima 5.23.2 for
this revised section, with display2d:false set in our init file. We first compute a 50 digit approximation
to the true root.
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
fpprec;
16
pi50 : ev (bfloat (%pi), fpprec:50);
3.1415926535897932384626433832795028841971693993751b0
slength( string (%));
53
We next define the symbolic cubic expression whose roots we would like to approximately calculate.
(%i4) e : expand ( (x-%pi)3);
(%o4) x3-3*%pi*x2+3*%pi2*x-%pi3
As a warm-up, we use the default 16 digit floating point precision and find the root(s) using both allroots
and bfallroots. We first need to turn the symbolic expression into a polynomial whose coefficients have
the default 16 digit accuracy.
(%i6) e_f16 : float (e);
(%o6) x3-9.424777960769379*x2+29.60881320326807*x-31.00627668029982
Now find the approximate roots of this numerical polynomial in x using allroots.
(%i7) sar16 : map (rhs, allroots (%i*e_f16));
(%o7) [3.14159265358979-1.8873791418627661E-15*%i,
9.9920072216264089E-16*%i+3.141592653589795,
8.8817841970012523E-16*%i+3.141592653589795]
We first check to see how well the approximate solutions behave as far as causing the approximate numerical
polynomial to be zero (as roots should do).
(%i8) for s in sar16 do (subst (s,x,e_f16), disp (expand (%%)))$
6.3108872417680944E-30*%i
-6.3108872417680944E-30*%i
-3.1554436208840472E-30*%i
12
We next compare the approximate roots (taking realpart) to pi50.
(%i9) for s in sar16 do disp (pi50 - realpart(s))$
3.663735981263017b-15
-1.665334536937735b-15
-1.665334536937735b-15
The above accuracy in finding corresponds to the default floating point precision being used.
Retaining the default precision, we try out bfallroots.
(%i10) sbfar16 : map (rhs, bfallroots (%i*e_f16));
(%o10) [3.141592653589788b0-1.207367539279858b-15*%i,
5.967448757360216b-16*%i+3.141592653589797b0,
6.106226635438361b-16*%i+3.141592653589795b0]
Thus we see that bfallroots provides no increased accuracy unless we set fpprec and ratepsilon to
values which will cause Maxima to use higher precision.
In order to demonstrate the necessity of setting ratepsilon, we first try out bfallroots using only the
fpprec setting. Lets try to solve for the roots with 40 digit accuracy, first converting the symbolic cubic to a
numerical cubic with coefficients having 40 digit accuracy.
(%i13) e_f40 : ev (bfloat (e),fpprec : 40);
(%o13) x3-9.424777960769379715387930149838508652592b0*x2
+2.960881320326807585650347299962845340594b1*x
-3.100627668029982017547631506710139520223b1
The coefficients are now big floats, with the tell-tale b0 or b1 power of ten factor attached to the end.
13
Now set fpprec : 40 and use bfallroots:
(%i16) fpprec:40$
(%i17) sbfar40 : map (rhs, bfallroots (%i*e_f40));
rat replaced -3.100627668029982017547631506710139520223B1
by -14821/478 = -3.100627615062761506276150627615062761506B1
rat replaced 2.960881320326807585650347299962845340594B1
by 32925/1112 = 2.960881294964028776978417266187050359712B1
rat replaced -9.424777960769379715387930149838508652592B0
by -103993/11034 = -9.424777959035707812216784484321189052021B0
(%o17) [5.444584912690149273860860372375096164019b-3*%i
+3.138436376741899641306089676703354562429b0,
3.138436376741899641306089676703354687072b0
-5.444584912690149273860860372375167833945b-3*%i,
7.166992586513730038213070271942264501126b-35*%i
+3.14790520555190852960460513091447980252b0]
which are really poor results, apparently caused by inaccurate rat replacement of decimal coefficients by
ratios of whole numbers. Look, for example, at the third rat replacemnt above and its difference from the actual
40 digit accurate number:
(%i20) bfloat (9.424777960769379715387930149838508652592B0 103993/11034 );
(%o20) 1.733671903171145665517319600570931418138b-9
(%i21) ratepsilon;
(%o21) 2.0E-8
14
So we are driven to the conclusion that, with the present design of Maxima, we must set ratepsilon to a
small number which somehow matches the setting of fpprec.
(%i22) ratepsilon : 1.0e-41$
(%i23) sbfar40 : map (rhs, bfallroots (%i*e_f40));
rat replaced -3.100627668029982017547631506710139520223B1
by -689775162029634828708/22246307389364524529
= -3.100627668029982017547631506710139520223B1
rat replaced 2.960881320326807585650347299962845340594B1
by 1094430324967716480409/36962991979932468848
= 2.960881320326807585650347299962845340594B1
rat replaced -9.424777960769379715387930149838508652592B0
by -787357891006146598194/83541266890691994833
= -9.424777960769379715387930149838508652592B0
(%o23) [3.141592653589793238462643383279502884197b0,
3.141592653589793238462643383279502884192b0
-2.066298663554802260101294694335978730541b-40*%i,
2.066298663554802260101294694335978730541b-40*%i
+3.141592653589793238462643383279502884203b0]
(%i24) for s in sbfar40 do (subst (s,x,e_f40), disp (expand (%%)))$
2.20405190779178907744138100729171064591b-39
0.0b0
7.346839692639296924804603357639035486367b-40
(%i25) for s in sbfar40 do disp (pi50 - realpart(s))$
9.183549615799121156005754197048794357958b-41
5.050952288689516635803164808376836896877b-39
-5.510129769479472693603452518229276614775b-39
15
9.2.5 Bigfloat Number Gaps and Binary Arithmetic
fpprec as set by the user is the number of DECIMAL digits being requested. In fact, the actual arithmetic is
carried out with binary arithmetic. Due to the inevitably finite number of binary bits used to represent a floating
point number there will be a range of floating point numbers which are not recognised as different.
For a simple example, lets take the case fpprec = 4. Consider the gap around the number x:bfloat(2/3)
whose magnitude is less than 1. We will find that ?fpprec has the value 16 and that Maxima behaves as if (for
this case) the fractional part of a bigfloat number is represented by the state of a system consisting of 18 binary
bits.
Let u = 218 . If we let x1 = x + u we get a number which is treated as having a nonzero difference from
x. However, if we let w be a number which is one significant digit less than u, and define x2 = x + w, x2 is
treated as having zero difference from x. Thus the gap in bigfloats around our chosen x is ulp = 2 218 = 217 ,
and this gap should be the same size (as long as fpprec = 4) for any bigfloat with a magnitude less than 1.
If we consider a bigfloat number whose decimal magnitude is less than 1, its value is represented by a fractional
binary number. For the case that this fractional binary number is the state of 18 (binary) bits, the smallest base
2 number which can occur is the state in which all bits are off (0) except the least significant bit which is on
(1), and the decimal equivalent of this fractional binary number is precisely 218 . Adding two bigfloats (each
of which has a decimal magnitude less than 1) when each is represented by the state of an 18 binary bit system
(interpreted as a fractional binary number), it is not possible to increase the value of any one bigfloat by less
than this smallest base 2 number.
(%i1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
(%o8)
(%i9)
(%o9)
fpprec:4$
?fpprec;
16
x :bfloat(2/3);
6.667b-1
u : bfloat(2(-18));
3.815b-6
x1 : x + u;
6.667b-1
x1 - x;
1.526b-5
x2 : x + 3.814b-6;
6.667b-1
x2 - x;
0.0b0
ulp : bfloat(2(-17));
7.629b-6
In computer science Unit in the Last Place, or Unit of Least Precision, ulp(x), associated with a floating
point number x is the gap between the two floating-point numbers closest to the value x. We assume here that
the magnitude of x is less than 1. These two closest numbers will be x + u and x u where u is the smallest
positive floating point number which can be accurately represented by the systems of binary bits whose states
are used to represent the fractional parts of the floating point numbers.
The amount of error in the evaluation of a floating-point operation is often expressed in ULP. We see that for
fpprec = 4, 1 ULP is about 8 106 . An average error of 1 ULP is often seen as a tolerable error.
16
We can repeat this example for the case fpprec = 16.
(%i10)
(%i11)
(%o11)
(%i12)
(%o12)
(%i13)
(%o13)
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
(%i17)
(%o17)
(%i18)
(%o18)
fpprec:16$
?fpprec;
56
x :bfloat(2/3);
6.666666666666667b-1
u : bfloat(2(-58));
3.469446951953614b-18
x1 : x + u;
6.666666666666667b-1
x1 - x;
1.387778780781446b-17
x2 : x + 3.469446951953613b-18;
6.666666666666667b-1
x2 - x;
0.0b0
ulp : bfloat(2(-57));
6.938893903907228b-18
16
see his draft paper Numerical Quadrature in a Symbolic/Numerical Setting, Oct. 16, 2008, available as the file quad.pdf in
the folder: http://www.cs.berkeley.edu/fateman/papers/
17
(%i4) fdf(g,1,10);
(%o4)
[4.7942553b-1, 1.834924b-18]
(%i5) fdf(g,1,10),fpprec:30;
(%o5)
[4.7942553b-1, 2.6824592b-33]
(%i6) fpprec;
(%o6)
16
In the first example, fpprec is 16, and increasing the value to 26 produces a change in the function value of
about 2 1018 . In the second example, fpprec is 30, and increasing the value to 40 produces a change in the
function value of about 3 1033 .
In the later section describing the tanh-sinh quadrature method, we will use this function for a heuristic
estimate of the contribution of floating point errors to the approximate numerical value produced for an integral
by that method.
9.3
(fpprintprec:8,load(brmbrg));
C:/PROGRA1/MAXIMA3.1/share/maxima/5.18.1/share/numeric/brmbrg.lisp
[brombergtol,brombergabs,brombergit,brombergmin,fpprec,fpprintprec];
[1.0b-4, 0.0b0, 11, 0, 16, 8]
tval: bfloat(integrate(exp(x),x,-1,1)),fpprec:42;
2.3504023b0
fpprec;
16
18
(%i5)
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
(%o8)
(%i9)
(%o9)
(brombergtol:0.0b0,brombergit:100)$
b15:(brombergabs:1.0b-15,bromberg(exp(x),x,-1,1) ),fpprec:30;
2.3504023b0
abs(b15 - tval),fpprec:42;
6.9167325b-24
b20:(brombergabs:1.0b-20,bromberg(exp(x),x,-1,1) ),fpprec:30;
2.3504023b0
abs(b20 - tval),fpprec:42;
1.5154761b-29
We see that, for the case of this test integral involving a well behaved integrand, the actual error of the result returned by bromberg is much smaller than the requested difference error supplied by the parameter
brombergabs.
For later use, we define qbromberg (in a file qbromberg.mac) with the code:
qbromberg(%f,a,b,rprec,fp, itmax ) :=
block([brombergtol,brombergabs,brombergit,
fpprec:fp ],
if rprec > fp then
( print(" rprec should be less than fp "),
return(done) ),
brombergabs : bfloat(10(-rprec)),
brombergtol : 0.0b0,
brombergit : itmax,
bromberg(%f(x),x,a,b) )$
This function, with the syntax
qbromberg ( f, a, b, rprec, fp, itmax )
uses the Maxima function bromberg to integrate the Maxima function f over the interval [a, b], setting
the local value of fpprec to fp, setting brombergtol to 0, setting brombergabs to 10rprec , where
rprec is called the requested precision.
Here is a test of qbromberg for this simple integral.
(%i10)
(%i11)
(%o11)
(%i12)
(%o12)
(%i13)
(%o13)
load(qbromberg)$
qbr20 : qbromberg(exp,-1,1,20,40,100);
2.3504023b0
abs(qbr20 - tval);
0.0b0
abs(qbr20 - tval),fpprec:40;
1.0693013b-29
We have to be careful in the above step-by-step method to set fpprec to a large enough value to see the actual
size of the error in the returned answer.
19
Instead of the work involved in the above step by step method, it is more convenient to define a function qbrlist
which is passed a desired fpprec as well as a list of requested precision goals for bromberg. The function
qbrlist then assumes a sufficiently accurate tval is globally defined, and proceeds through the list to calculate the bromberg value for each requested precision, computes the error in the result, and prints a line containing (rprec, fpprec, value, value-error). Here is the code for such a function, available in qbromberg.mac:
qbrlist(%f,a,b,rplist,fp,itmax) :=
block([fpprec:fp,fpprintprec,brombergtol,
brombergabs,brombergit,val,verr,pr],
if not listp(rplist) then (print("rplist # list"),return(done)),
brombergtol : 0.0b0,
brombergit : itmax,
fpprintprec:8,
print(" rprec
fpprec
val
verr "),
print(" "),
for pr in rplist do
( brombergabs : bfloat(10(-pr)),
val: bromberg(%f(x),x,a,b),
verr: abs(val - tval),
print(" ",pr,"
",fp,"
",val,"
",verr) ) )$
and here is an example of use of qbrlist in which the requested precision rprec (called pr in the code) is
set to three different values supplied by the list rplist for each setting of fpprec used. We first define an
accurate comparison value tval:
(%i1) (fpprintprec:8, load(brmbrg), load(qbromberg))$
(%i2) tval: bfloat(integrate(exp(x),x,-1,1)),fpprec:42;
(%o2)
2.3504023b0
We see that with fpprec equal to 40, increasing rprec from 30 to 35 results in no improvement in the actual
error of the result.
20
When bromberg Fails
If the integrand has end point algebraic and/or logarithmic singularities, bromberg
may fail. Here is an example
R1
in which the integrand has a logarithmic singularity at the lower end point: 0 t ln(t) dt. The integrate
function has no problem with this integral.
(%i6) g(x):= sqrt(x)*log(x)$
(%i7) integrate(g(t),t,0,1);
4
- 9
(%o7)
(%i8) (load(brmbrg),load(qbromberg))$
(%i9) qbromberg(g,0,1,30,40,100);
log(0) has been generated.
#0: qbromberg(%f=g,a=0,b=1,rprec=30,fp=40,itmax=100)
-- an error. To debug this try debugmode(true);
You can instead use the tanh-sinh quadrature method for this integral (see Sec. 9.3.3).
9.3.2 A Double Exponential Quadrature Method for a x <
This method (H. Takahasi and M. Mori, 1974; see Sec 9.3.3) is effective for integrands which contain a factor
with some sort of exponential damping as the integration variable becomes large.
R
R
An integral of the form a g(y) dy can be converted into the integral 0 f (x) dx by making the change of
variable of integration y x given by y = x + a. Then f (x) = g(x + a).
The double exponential method used here then converts the integral
using a variable transformation x u:
R
0
F(u) du
(9.1)
and hence
F(u) = f (x(u)) w(u),
You can confirm that x(0) = exp(1),
where
w(u) =
dx
= exp(exp(u)) + x(u).
du
(9.2)
x() = .
Because of the rapid decay of the integrand when the magnitude of u is large, one can approximate the value of
the infinite domain u integral by using a trapezoidal numerical approximation with step size h using a modest
number (2 N + 1) of function evaluations.
I(h, N) ' h
N
X
F(uj )
where
uj = j h
(9.3)
j = N
21
(%i4) load(quad_de);
(%o4)
c:/work3/quad_de.mac
(%i5) quad_de(g,0,30,40);
(%o5)
[1.0b0, 4, 4.8194669b-33]
(%i6) abs(first(%) - tval),fpprec:45;
(%o6)
9.1835496b-41
The package function quad_de(f, a, rp, fp) integrates the Maxima function f over the domain [x a],
using fpprec : fp, and returns a three element list when vdiff (the absolute value of the difference obtained
for the integral in successive k levels) becomes less than or equal to 10rp . The parameter rp is called the
requested precision, and the value of h is repeatedly halved until the vdiff magnitude either satisfies this
criterion or starts increasing. The first element is the appoximate value of the integral. The second element (4
above) is the final k-level used, where h = 2k . The third and last element is the final value of vdiff. We see
in the above example that requesting precision rp = 30 and using floating point precision fpprec : 40 results
in an answer good to about 40 digits. This sort of accuracy is typical.
The package function idek(f, a, k, fp) integrates the Maxima function f over the domain [a, ] using
a k-level approximation with h = 1/2k and fpprec : fp.
(%i7) idek(g,0,4,40);
(%o7)
(%i8) abs(% - tval),fpprec:45;
(%o8)
1.0b0
9.1835496b-41
The package function idek_e(f, a, k, fp) does the same calculation as idek(f, a, k, fp), but returns
both the approximate value of the integral and also a rough estimate of the amount of the error which is due
to the floating point arithmetic precision being used. (The error of the approximation has three contributions:
1. the quadrature algorithm being used, 2. the step size h being used, and 3. the precision of the floating point
arithmetic being used.)
(%i9) idek_e(g,0,4,40);
(%o9)
[1.0b0, 8.3668155b-42]
(%i10) abs(first(%) - tval),fpprec:45;
(%o10)
9.1835496b-41
The package function ide(f, a, rp, fp) follows the same path as quad_de(f, a, rp, fp), but
shows the progression toward success as the k level increases ( and h decreases ):
(%i11) ide(g,0,30,40);
rprec = 30 fpprec = 40
k
value
vdiff
1
1.0b0
2
1.0b0
4.9349774b-8
3
9.9999999b-1
4.8428706b-16
4
1.0b0
4.8194669b-33
22
The package function ide_test(f, a, rp, fp) follows the path of ide(f, a, rp, fp), but adds
to the table the value of the error of the approximate result for each k level attempted. The use of this function
depends on an accurate value of the integral being bound to the global variable tval.
(%i12) ide_test(g,0,30,40);
rprec = 30 fpprec = 40
k
value
vdiff
1
1.0b0
2
1.0b0
4.9349774b-8
3
9.9999999b-1
4.8428706b-16
4
1.0b0
4.8194669b-33
verr
4.9349775b-8
4.8428706b-16
4.8194668b-33
9.1835496b-41
Test Integral 1
Here we test this double exponential method code with the known integral
Z t
e
dt =
t
0
(%i13)
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
(%i17)
(%o17)
(%i18)
(%o18)
(9.4)
g(x):= exp(-x)/sqrt(x)$
integrate(g(t),t,0,inf);
sqrt(%pi)
tval : bfloat(%),fpprec:45;
1.7724538b0
quad_de(g,0,30,40);
[1.7724538b0, 4, 1.0443243b-34]
abs(first(%) - tval),fpprec:45;
1.8860005b-40
idek_e(g,0,4,40);
[1.7724538b0, 2.7054206b-41]
Again we see that the combination rp = 30, fp = 40 leads to an answer good to about 40 digits of precision.
Test Integral 2
Our second known integral is
2 /2
et
dt =
/2
(%i19)
(%i20)
(%i21)
(%o21)
(%i22)
(%o22)
(%i23)
(%o23)
g(x) := exp(-x2/2)$
tval : bfloat(sqrt(%pi/2)),fpprec:45$
quad_de(g,0,30,40);
[1.2533141b0, 5, 1.099771b-31]
abs(first(%) - tval),fpprec:45;
2.1838045b-40
idek_e(g,0,5,40);
[1.2533141b0, 1.3009564b-41]
(9.5)
23
Test Integral 3
Our third test integral is
et cos t dt = 1/2
(9.6)
(%o25)
(%i26)
(%i27)
(%o27)
(%i28)
(%o28)
(%i29)
(%o29)
tval : bfloat(%),fpprec:45$
quad_de(g,0,30,40);
[5.0b-1, 5, 1.7998243b-33]
abs(first(%) - tval),fpprec:45;
9.1835496b-41
idek_e(g,0,5,40);
[5.0b-1, 9.8517724b-42]
(9.7)
sinh u
(9.8)
u x 1, u x 1
(9.9)
24
The weight w(u) = dx(u)/du is
w(u) =
cosh u
2
2
cosh 2 sinh u
(9.10)
with the property w(u) = w(u), in terms of which F(u) = f (x(u) w(u). Moreover, F(u) has double
exponential behavior of the form
N
X
F(uj )
where
uj = j h
(9.12)
j = N
...working...
A value of the integral accurate to about 45 digits is bound to the symbol tval. The package function
bfprint(bf, fpp) allows controlled printing of fpp digits of the true value tval to the screen. We then
compare the approximate quadrature result with this true value. The package quad_ts.mac defines two
global parameters. _kmax% is the maximum k-level possible (the defined default is 8, which means the
minimum step size for the transformed u-integral is du = h = 1/28 = 1/256. The actual k-level needed
to return a result with the requested precision rp is the integer in the second element of the returned list. The
global parameter _epsfac% (default value 2) is used to decide how many (y, w) numbers to pre-compute
(see below).
25
We see that a k-level approximation with k = 5 and h = 1/25 = 1/32 returned an answer with an actual
precision of about 40 digits (when rp = 30 and fp = 40).
The first time 40 digit precision arithmetic is called for, a set of (y, w) numbers are calculated and stored in an
array which we call _yw%[8, 40]. The y(u) values will later be converted to x(u) numbers using high
precision, and the original integrand function f(x(u)) is also calculated at high precision. The w(u) numbers are what we call weights, and are needed for the numbers F(u) = f (x(u)) w(u) used in the trapezoidal
rule evaluation. The package precomputes pairs (y, w) for larger and larger values of u until the magnitude
of the weight w becomes less than eps, where eps = 10n p , where n is the global parameter _epsfac%
(default 2) and p is the requested floating point precision fp.
Once the set of 40-digit precision (y, w) numbers have been pre-computed, they can be used for the
evaluation of any similar precision integrals later, since these numbers are independent of the actual function
being integrated, but depend only on the nature of the tanh-sinh transformation being used.
The package function qtsk(f, a, b, k, fp) (note: arg k replaces rp ) integrates the Maxima function
f over the domain [a, b] using a k-level approximation with h = 1/2k and fpprec : fp.
(%i7) qtsk(exp,-1,1,5,40);
(%o7)
(%i8) abs(% - tval),fpprec:45;
(%o8)
2.3504023b0
2.719612b-40
A heuristic value of the error contribution due to the arithmetic precision being used (which is separate from
the error contribution due to the nature of the algorithm and the step size being used) can be found by using
the package function qtsk_e(f, a, b, k, fp);. The first element of the returned list is the value of
the integral, the second element of the returned list is a rough estimate of the contribution of the floating point
arithmetic precision being used to the error of the returned answer.
(%i9) qtsk_e(exp,-1,1,5,40);
(%o9)
[2.3504023b0, 2.0614559b-94]
(%i10) abs(first(%) - tval),fpprec:45;
(%o10)
2.719612b-40
The very small estimate of the arithmetic precision contribution (two parts in 1094 ) to the error of the
answer is due to the high precision being used to convert from the pre-computed y to the needed abcissa x via
x : bfloat(1 y) and the subsequent evaluation f (x). The precision being used depends on the size of the
smallest y number, which will always be that appearing in the last element of the hashed array _yw%[8, 40].
(%i11) last(_yw%[8,40]);
(%o11)
[4.7024891b-83, 8.9481574b-81]
(In Eq. (9.12) we have separated out the (u = 0, x = 0) term, and used the symmetry properties x(u) = x(u),
and w(u) = w(u) to write the remainder as a sum over positive values of u (and hence positive values of x)
so only the large u values of y(u) need to be pre-computed).
We see that the smallest y number is about 5 1083 and if we subtract this from 1 we will get 1 unless we
use a very high precision. It turns out that as u approaches plus infinity, x (as used here) approaches b (which
is 1 in our example) from values less than b. Since a principal virtue of the tanh-sinh method is its ability to
handle integrands which blow up at the limits of integration, we need to make sure we stay away (even if
26
only a little) from those end limits.
We can see the precision with which the arithmetic is being carried out in this crucial step by using the fpxy(fp)
function
(%i12) fpxy(40)$
the last y value = 4.7024891b-83
the fpprec being used for x and f(x) is
93
and this explains the small number returned (as the second element) by qtsk_e(exp, -1, 1, 5, 40);.
The package function qts(f, a, b, rp, fp) follows the same path as quad_ts(f, a, b, rp, fp),
but shows the progression toward success as the k level increases ( and h decreases ):
(%i13) qts(exp,-1,1,30,40)$
rprec = 30
fpprec = 40
k
newval
vdiff
1
2.350282b0
2
2.3504023b0
1.2031242b-4
3
2.3504023b0
8.136103b-11
4
2.3504023b0
1.9907055b-23
5
2.3504023b0
0.0b0
The package function qts_test(f, a, b, rp, fp) follows the path of qts(f, a, b, rp, fp),
but adds to the table the value of the error of the approximate result for each k level attempted. The use of this
function depends on an accurate value of the integral being bound to the global variable tval.
(%i14) qts_test(exp,-1,1,30,40)$
rprec = 30 fpprec = 40
k
value
vdiff
1
2.350282b0
2
2.3504023b0
1.2031242b-4
3
2.3504023b0
8.136103b-11
4
2.3504023b0
1.9907055b-23
5
2.3504023b0
0.0b0
verr
1.2031234b-4
8.136103b-11
1.9907055b-23
2.7550648b-40
2.7550648b-40
Test Integral 1
Here we test this tanh-sinh method code with the known integral which confounded bromberg in Sec. 9.3.1 :
Z 1
t ln(t) dt = 4/9
(9.13)
0
(%i15)
(%i16)
(%o16)
(%i17)
(%o17)
(%i18)
(%o18)
(%i19)
(%o19)
g(x):= sqrt(x)*log(x)$
tval : bfloat(integrate(g(t),t,0,1)),fpprec:45;
- 4.4444444b-1
quad_ts(g,0,1,30,40);
[- 4.4444444b-1, 5, 3.4438311b-41]
abs(first(%) - tval),fpprec:45;
4.4642216b-41
qtsk_e(g,0,1,5,40);
[- 4.4444444b-1, 7.6556481b-43]
Requesting thirty digit accuracy with forty digit arithmetic returns a value for this integral which has about
forty digit precision. Note that vdiff is approximately the same as the actual absolute error.
27
Test Integral 2
Consider the integral
1
0
arctan( 2 + t2 )
dt = 5 2 /96.
2
2
(1 + t ) 2 + t
(9.14)
Test Integral 3
We consider the integral
t
dt = 2 (3/4)/(1/4)
1 t2
(9.15)
28
An alternative route to the true value is to convert beta to gammas using makegamma:
(%i35) makegamma(%o30);
3
2 sqrt(%pi) gamma(-)
4
-------------------1
gamma(-)
4
(%o35)
(%i36) float(%);
(%o36)
(%i37) bfloat(%o11),fpprec:45;
(%o37)
1.1981402
1.1981402b0
Test Integral 4
We next consider the integral
ln2 t dt = 2
(9.16)
(%i38)
(%i39)
(%o39)
(%i40)
(%o40)
(%i41)
(%o41)
(%i42)
(%o42)
g(x) := log(x)2$
integrate(g(t),t,0,1);
2
quad_ts(g,0,1,30,40);
[2.0b0, 5, 0.0b0]
abs( first(%) - bfloat(2) ),fpprec:45;
1.8367099b-40
qtsk_e(g,0,1,5,40);
[2.0b0, 1.2570464b-42]
Test Integral 5
We finally consider the integral
/2
ln(cos t) dt = ln(2)/2
0
(9.17)
29
(%i46)
(%o46)
(%i47)
(%o47)
(%i48)
(%o48)
(%i49)
(%o49)
(%i50)
(%o50)
(%i51)
(%o51)
float(-%pi*log(2)/2);
- 1.088793
tval : bfloat(-%pi*log(2)/2),fpprec:45;
- 1.088793b0
quad_ts(g,0,%pi/2,30,40);
[1.2979374b-80 %i - 1.088793b0, 5, 9.1835496b-41]
ans: realpart( first(%) );
- 1.088793b0
abs(ans - tval),fpprec:45;
1.9661653b-40
qtsk_e(g,0,%pi/2,5,40);
[1.2979374b-80 %i - 1.088793b0, 2.4128523b-42]
We see that the tanh-sinh result includes a tiny imaginary part due to bigfloat errors, and taking the real part
produces an answer good to about 40 digits (using rp = 30, fp = 40).
References for the tanh-sinh Quadrature Method
This method was initially described in the article Double Exponential Formulas for Numerical Integration, by Hidetosi
Takahasi and Masatake Mori, in the journal Publications of the Research Institute for Mathematical Sciences ( Publ.
RIMS), vol.9, Number 3, (1974), 721-741, Kyoto University, Japan. A recent summary by the second author is Discovery
of the Double Exponential Transformation and Its Developments, by Masatake Mori, Publ. RIMS, vol.41, Number 4,
(2005), 897-935. Both of the above articles can be downloaded from the Project Euclid RIMS webpage
http://projecteuclid.org/
DPubS?service=UI&version=1.0&verb=Display&page=past&handle=euclid.prims
A good summary of implementation ideas can be found in the report Tanh-Sinh High-Precision Quadrature, by David
H. Bailey, Jan. 2006, LBNL-60519, which can be downloaded from the webpage
http://crd.lbl.gov/dhbailey/dhbpapers/
30
Since one can always make a change of integration variable from the domain [a, b] to the integration domain
[-1, 1], this method approximates an integral over [-1, 1] as the sum
Z
f (x) dx
1
N
X
wj f (xj )
(9.18)
j=1
where the xj are the roots of the N-th degree Legendre polynomial PN (x) on [-1, 1], and the weights wj are
wj =
2
(N +
(9.19)
This method is implemented with our Ch.9 package file quad_gs.mac, and Richard Fatemans lisp file:
http://www.cs.berkeley.edu/fateman/generic/quad-maxima.lisp
R1
1
ex dx.
The package function gaussunit(f, N) integrates the Maxima function f over the domain [1, 1] using N point
Gauss-Legendre quadrature.
(%i1) load("quad-maxima.lisp");
(%o1)
quad-maxima.lisp
(%i2) fpprintprec:8$
(%i3) tval : bfloat(integrate(exp(x),x,-1,1)),fpprec:45;
(%o3)
2.3504023b0
(%i4) load(quad_gs);
(%o4)
c:/work3/quad_gs.mac
(%i5) arrays;
(%o5)
[ab_and_wts]
(%i6) arrayinfo(ab_and_wts);
(%o6)
[hashed, 2]
(%i7) gaussunit(exp,4);
(%o7)
2.350402b0
(%i8) abs(% - tval),fpprec:45;
(%o8)
2.9513122b-7
(%i9) fpprec;
(%o9)
16
(%i10) arrayinfo(ab_and_wts);
(%o10)
[hashed, 2, [4, 16]]
(%i11) first( ab_and_wts[4, 16] );
(%o11)
[8.6113631b-1, 3.3998104b-1]
(%i12) second( ab_and_wts[4, 16] );
(%o12)
[3.4785484b-1, 6.5214515b-1]
31
(%o13)
4
2
35 x
15 x
3
----- - ----- + 8
4
8
(%i14) float(solve(lp4));
(%o14)
[x = - 0.861136, x = 0.861136, x = - 0.339981, x = 0.339981]
With the default value of fpprec = 16 and using only four integrand evaluation points, the error is about 2
parts in 107 . The first element of the two index hashed array ab_and_wts[4,16] is a list of the positive
zeros of the fourth order Legendre polynomial P4 (x) ( calculated with the arithmetic precision fpprec = 16).
That fourth order Legendre polynomial P4 (x) can be displayed with this package using legenp(4, x).
Using solve we see that the roots for negative x are simply the the positive roots with a minus sign, so the
algorithm used makes use of this symmetry and keeps track of only the positive roots.
We can verify that the list of roots returned is correct to within the global floating point precision (we do this
two different ways):
(%i15) lfp4(x) := legenp(4,x)$
(%i16) map(lfp4,%o11);
(%o16)
[0.0b0, - 3.4694469b-18]
(%i17) map( lambda([z],legenp(4,z)),%o11 );
(%o17)
[0.0b0, - 3.4694469b-18]
The second element of ab_and_wts[4,16] is a list of the weights which are associated with the positive
roots (the negative roots have the same weights), with order corresponding to the order of the returned positive
roots.
The package function gaussunit_e(f, N) does the same job as gaussunit(f, N), but returns a
rough estimate of the amount contributed to the error by the floating point precision used (as the second element
of a list:
(%i18) gaussunit_e(exp,4);
(%o18)
[2.350402b0, 1.2761299b-17]
We see that the error attributable to the floating point precision used is insignificant compared to the error due
to the low number of integrand evaluation points for this example.
An arbitrary finite integration interval is allowed with the functions gaussab(f, a, b, N) and
gaussab_e(f, a, b, N) which use N point Gauss-Legendre quadrature over the interval [a, b], with the
latter function being the analog of gaussunit_e(f, N).
(%i19) gaussab(exp,-1,1,4);
(%o19)
2.350402b0
(%i20) abs(% - tval),fpprec:45;
(%o20)
2.9513122b-7
(%i21) gaussab_e(exp,-1,1,4);
(%o21)
[2.350402b0, 1.2761299b-17]
32
The package function quad_gs (f, a, b, rp ) integrates the Maxima function f over the finite interval [a, b], successively doubling the number of integrand evaluation points, stopping when the absolute value
of the difference (In In/2 ) is less than 10rp (rp is the requested precision for the result), using the global
setting of fpprec to use the corresponding precision arithmetic. We emphasize that Fatemans code uses a
global setting of fpprec to achieve higher precision quadrature, rather than the method used in the previous two
sections in which fpprec was set locally inside a block. This function returns the list
[ approx-value, number-function-evaluations, abs(vdiff) ], where the last element
should be smaller than 10rp .
Here we test this function for fpprec = 16, 30, and 40.
(%i22) quad_gs(exp,-1,1,10);
fpprec = 16
(%o22)
[2.3504023b0, 20, 6.6613381b-16]
(%i23) abs(first(%) -tval),fpprec:45;
(%o23)
6.2016267b-16
(%i24) fpprec:30$
(%i25) quad_gs(exp,-1,1,20);
fpprec = 30
(%o25)
[2.3504023b0, 20, 1.2162089b-24]
(%i26) abs(first(%) -tval),fpprec:45;
(%o26)
2.2001783b-30
(%i27) fpprec:40$
(%i28) quad_gs(exp,-1,1,30);
fpprec = 40
(%o28)
[2.3504023b0, 40, 1.8367099b-40]
(%i29) abs(first(%) -tval),fpprec:45;
(%o29)
2.7905177b-40
(%i30) gaussab_e(exp,-1,1,40);
(%o30)
[2.3504023b0, 1.8492214b-41]
We have checked the contribution to the error due to the forty digit arithmetic precision used, with N = 40
point Gauss-Legendre quadrature (remember that N is the middle element of the list returned by
quad_gs (f, a, b, rp ) and is also the last argument of the function gaussab_e(f, a, b, N).
We see that requesting 30 digit precision for the answer while using the global fpprec set to 40 results in an
answer good to about 39 digits. Finally, lets check on what abscissae and weight arrays have been calculated
so far:
(%i31) arrayinfo(ab_and_wts);
(%o31) [hashed, 2, [4, 16], [10, 16], [10, 30], [10, 40], [20, 16], [20, 30],
[20, 40], [40, 40]]
Using quad_gs (f, a, b, rp ) with fpprec = 16 led to the calculation of the abscissae and weight
array for the index pairs [10,16] and [20,16] before the requested precision was achieved (the function always starts with N = 10 point quadrature and then successively doubles that number until success is
achieved).
Using quad_gs (f, a, b, rp ) with fpprec = 30 led to the calculation of the abscissae and weight
array for the index pairs [10,30] and [20,30] before the requested precision was achieved.
33
Using quad_gs (f, a, b, rp ) with fpprec = 40 led to the calculation of the abscissae and weight
array for the index pairs [10,40], [20,40], and [40,40] before the requested precision was achieved.
Finally, we have the function quad_gs_table(f, a, b, rp) which prints out a table showing the progression toward success:
(%i32) quad_gs_table(exp,-1,1,30)$
new val
2.3504023b0
2.3504023b0
2.3504023b0
N
10
20
40
fpprec = 40
vdiff
1.2162183b-24
1.8367099b-40
10.1 Introduction
In chapter 10 we discuss the Fourier series expansion of a given function, the computation of Fourier transform
integrals, and the calculation of Laplace transforms (and inverse Laplace transforms).
X
1
f (x) = a0 +
[an cos(n x) + bn sin(n x)]
(10.1)
2
n=1
and the constant coefficients (an , bn ) are
Z
1
an =
f (y) cos(n y) dy,
1
bn =
(10.2)
(For a derivation of these equations see Sec.10.2.8 and Eqs.(10.20) and (10.21).)
Whether or not you are working with a function which is periodic, the Fourier expansion will represent a periodic function for all x, in this case having period 2 .
The first term of the expansion
1
1
a0 =
2
2
f (y) dy = hf (x)i
(10.3)
is the (un-weighted) average of f(x) over the domain (, ). Hence a0 will always be twice the average value
of the function over the domain.
If f(x) is an even function (f (x) = f (x)), then only the cos(n x) terms contribute. If f(x) is an odd function
(f (x) = f (x)), then only the sin(n x) terms contribute.
If you are trying to find a fourier expansion for a function or expression f(x) which is a homemade function
which involves if..then..else constructs, it is necessary to do the preliminary work by hand.
On the other hand, if the given function is a smooth function defined in terms of elementary functions and
polynomials, or includes abs of elements of the function, one can use the fourie package to do most of the
work in obtaining the desired Fourier series expansion. This package is calculus/fourie.mac, and there
is also a short demo file fourie.dem.
Although many secondary functions defined in this mac file are usable once you load the package, they are not
documented in the Maxima manual. The Maxima manual gives a brief definition of the primary tools available,
but gives no examples of use, nor is there an example file for such primary functions as fourier, foursimp, and
fourexpand.
If the Fourier series integrals needed for the coefficients are too difficult for integrate, you should use the
Quadpack function quad_qawo described in Chapter 8, Numerical Integration.
The list contains, in order, the lowest approximation 2 sin(x) which retains only the n = 1 term in the expansion, the two term approximation 2 sin(x) sin(2 x), which includes the n = 1, 2 terms, etc. We now load
the draw package and the qdraw package (the latter available with Ch. 5 material on the authors webpage) to
make two simple plots. We first make a plot showing the function f (x) = x in blue, the one term approximation
(fs(1) = 2 sin(x)) in red, and the two term approximation (fs(2) = 2 sin(x) - sin(2 x)) in green.
(%i6) (load(draw), load(qdraw) )$
qdraw(...), qdensity(...), syntax: type qdraw();
(%i7) qdraw( xr(-5.6,5.6),yr(-4,4),
ex([x,fs(1),fs(2)],x,-%pi,%pi),key(bottom) )$
In this plot (see next page), we have taken control of the x and y range, using the approximate fudge factor 1.4
to relate the horizontal canvas extent to the vertical canvas extent (see our discussion in Ch. 5 if this is all new
to you) to get the geometry approximately correct. In the next plot we include one, two, three and four term
approximations.
(%i8) qdraw( xr(-5.6,5.6),yr(-4,4),
ex([x,fs(1),fs(2),fs(3),fs(4)],x,-%pi,%pi),key(bottom) )$
with the four term approximation in purple being a closer approximation to f (x) = x (see the figure on the next
page).
4
3
2
1
0
-1
-2
1
2
3
-3
-4
-4
-2
4
3
2
1
0
-1
-2
1
2
3
4
5
-3
-4
-4
-2
Finally, after dealing with possible instances of abs(..) in the function to be expanded, adefint calls either
ldefint or integrate with an argument involving these same n dependent trig functions.
Here is a small test of that leakage for both an assume statement and a declare statement.
(%i1) facts();
(%o1)
[]
(%i2) f(m) := block([n],declare(n,integer),assume( n > 0 ),
if m < 2 then n :2 else n:3,(2*n*m) )$
(%i3) f(1);
(%o3)
4
(%i4) facts();
(%o4)
[kind(n, integer), n > 0]
(%i5) is(n>0);
(%o5)
true
Another curious feature of the fourie.mac package is that n is not declared to be an integer, and unless
the user of the package does this first, the integration routine may ask questions about signs which may seem
irrelevant to the result. We avoid that trap here and use declare(n, integer) before calling fourier.
(%i1)
(%o1)
(%i2)
(%o2)
(%i3)
(%o3)
(%i4)
(%t4)
(%t5)
(%t6)
facts();
[]
(load(fourie), facts() );
[]
(declare(n,integer), facts() );
[kind(n, integer)]
clist : fourier(x,x,%pi);
a = 0
0
a = 0
n
n
2 (- 1)
b = - -------n
n
(%o6)
[%t4, %t5, %t6]
(%i7) facts();
(%o7)
[kind(n, integer), n > 0]
(%i8) fs(nmax) := fourexpand(clist,x,%pi, nmax )$
(%i9) map( fs, [1,2,3,4] );
2 sin(3 x)
(%o9) [2 sin(x), 2 sin(x) - sin(2 x), ---------- - sin(2 x) + 2 sin(x),
3
sin(4 x)
2 sin(3 x)
- -------- + ---------- - sin(2 x) + 2 sin(x)]
2
3
(%i10) b(n);
(%o10)
b(n)
Some comments: you can use foursimp to get extra simplification of the fourier coefficients (if needed) before
defining what I call clist (for coefficient list) which is the list fourexpand needs to generate the expansions
you want. Note fourier produces a separate output for a0 and an , with the second meant for n = 1, 2, . . .,
and there is never an output for b0 . We have defined the small function fs(nmax) to make it easier to call
6
fourexpand with any value of nmax and to allow the function to be mapped onto a list of integers to show
us the first few approximations. Note that once you call fourier, the assumption n > 0 becomes a global fact.
Also note that the fourie.mac package does not define a Maxima function b(n), although you could use:
(%i11) define(b(n),rhs(%t6) );
n
2 (- 1)
(%o11)
b(n) := - -------n
(%i12) map( b, makelist(i,i,1,7) );
2
1 2
1 2
(%o12)
[2, - 1, -, - -, -, - -, -]
3
2 5
3 7
If you look at the Maxima code in fourie.mac, you see that because we have an odd function f (x) = x,
fourier calls the package function foursin, which calls package function adefint, which calls the core Maxima
function ldefint for this case.
Those expansion expressions can then be used for plots as above.
10.2.4 Fourier Series Expansion of a Function Over (p, p)
The Fourier series expansion of a function defined over the interval p x p (and whose Fourier expansion
will represent a function which has a period 2 p) can be found from the expansion over the interval (, )
which we have been using above by a simple change of variables in the integrals which appear in Eqs.(10.2)
and (10.1).
However, we will simply use the results derived in Sec.10.2.8, and written down in Eqns (10.18) and (10.19).
X
nx
nx
1
f (x) = a0 +
an cos
+ bn sin
2
p
p
n=1
with the corresponding coefficients (for an , n = 0, 1, ..., for bn , n = 1, ...):
Z
Z
ny
ny
1 p
1 p
an =
f (y) cos
dy, bn =
f (y) sin
dy.
p p
p
p p
p
(10.4)
(10.5)
We need to warn the user of the package fourie.mac that they use the symbol a0 to mean our a0 /2.
Our a0 is defined by
1
a0 =
p
f (x) dx
(10.6)
1
=
2p
f (x) dx
(10.7)
which defines the average value of the function over the domain and which becomes the first term of the fourier
series expansion they provide.
so we will split up the region of integration into two sub-intervals: 2 x 0, in which |x| = x, and the
interval 0 x 2 in which |x| = x. We will use the formula Eq. (10.5) for the coefficients an (note that
an = 0 if n is even) and the expansion formula Eq. (10.4).
(%i1) (declare(n,integer),assume(n > 0), facts() );
(%o1)
[kind(n, integer), n > 0]
(%i2) a0 :integrate(-x,x,-2,0)/2 + integrate(x,x,0,2)/2;
(%o2)
2
(%i3) an : integrate((-x)*cos(n*%pi*x/2),x,-2,0)/2 +
integrate(x*cos(n*%pi*x/2),x,0,2)/2;
n
4 (- 1)
4
(%o3)
-------- - ------2 2
2 2
%pi n
%pi n
(%i4) an : (ratsimp(an), factor(%%) );
n
4 ((- 1) - 1)
(%o4)
-------------2 2
%pi n
(%i5) define(a(n),an);
n
4 ((- 1) - 1)
(%o5)
a(n) := -------------2 2
%pi n
(%i6) map( a, [1,2,3,4,5] );
8
8
8
(%o6)
[- ----, 0, - ------, 0, - -------]
2
2
2
%pi
9 %pi
25 %pi
(%i7) fs(nmax) := a0/2 + sum(a(m)*cos(m*%pi*x/2),m,1,nmax)$
The first function in the plot list is |x|, represented by abs(x), which appears in the color blue. We see that the
expansion out to n = 5 provides a close fit to |x|. Here is that comparison:
1.5
0.5
1
2
0
-2
-1.5
-1
-0.5
0.5
1.5
(%i3) fourier(abs(x),x,2);
(%t3)
(%t4)
(%t5)
(%o5)
(%i6) clist : foursimp(%);
(%t6)
(%t7)
(%t8)
a = 1
0
n
4 (- 1)
4
a = -------- - ------n
2 2
2 2
%pi n
%pi n
b = 0
n
[%t3, %t4, %t5]
a = 1
0
n
4 ((- 1) - 1)
a = -------------n
2 2
%pi n
b = 0
n
(%o8)
[%t6, %t7, %t8]
(%i9) facts();
(%o9)
[kind(n, integer), n > 0]
(%i10) fs(nmax) := fourexpand(clist,x,2,nmax )$
(%i11) map( fs, [1,3,5] );
%pi x
3 %pi x
%pi x
8 cos(-----)
8 cos(-------)
8 cos(-----)
2
2
2
(%o11) [1 - ------------, - -------------- - ------------ + 1,
2
2
2
%pi
9 %pi
%pi
5 %pi x
3 %pi x
%pi x
8 cos(-------)
8 cos(-------)
8 cos(-----)
2
2
2
- -------------- - -------------- - ------------ + 1]
2
2
2
25 %pi
9 %pi
%pi
Notice that (a0 )fourie = 1 = 12 (a0 )ourdef , (see Eq. (10.7) ) so that fourie.macs expansion starts off with
the term a0 rather than 21 a0 . Of course, the actual end results look the same, with the first term in this example
being 1, which is the average value of |x| over the domain (2, 2).
Here we chose to use the package function foursimp to simplify the appearance of the coefficients. We see
that fourie.mac is able to cope with the appearance of abs(x) in the integrand, and produces the same
coefficients and expansions as were found by hand.
10
The plot of f(x) shows a square pulse with height 3/2 above the x axis and with a width of 2 units over the
interval 1 x 1. Over the rest of the domain 2 x 2, f(x) is defined to be zero.
2
1.5
0.5
-0.5
-2
-1.5
-1
-0.5
0.5
1.5
Hence we must compute the Fourier series expansion by hand. We see that f(x) is an even function
(f (x) = f (x)), so only the cos(n x/2) terms will contribute, so we only need to calculate the an coefficients.
(%i6) (declare(n,integer), assume(n>0),facts() );
(%o6)
[kind(n, integer), n > 0]
11
We see that for n > 0, an = 0 for n even, and the non-zero coefficients have n = 1, 3, 5, 7, .... Hence we only
get a better approximation if we increase nmax by 2 each time.
(%i10) fs(nmax) := a0/2 + sum( a(m)*cos(m*%pi*x/2),m,1,nmax )$
(%i11) map( fs, [1,3] );
%pi x
3 %pi x
%pi x
3 cos(-----)
cos(-------)
3 cos(-----)
2
3
2
2
3
(%o11)
[------------ + -, - ------------ + ------------ + -]
%pi
4
%pi
%pi
4
(%i12) qdraw( yr(-0.5,2),ex([f(x),fs(1),fs(3) ],x,-2,2) )$
(%i13) qdraw( yr(-0.5,2),ex([f(x),fs(11) ],x,-2,2) )$
The plot with the approximations fs(1) and fs(3) was drawn first.
2
1
2
3
1.5
0.5
-0.5
-2
-1.5
-1
-0.5
0.5
1.5
12
1
2
1.5
0.5
-0.5
-2
-1.5
-1
-0.5
0.5
1.5
-5
10
13
Since we have an odd function, only terms like bn sin(n x/10) will contribute to the expansion, but, just for
practice, we find an too.
(%i5) a0 : (1/10)*( integrate( -5, x, -5, 0 ) +
integrate( 5, x, 0, 5 ) );
(%o5)
0
(%i6) an : (1/10)*(integrate( -5*cos( n*%pi*x/10 ), x, -5, 0 )
integrate(5*cos(n*%pi*x/10), x, 0, 5 )
(%o6)
0
(%i7) bn : ( (1/10)*(integrate( -5*sin(n*%pi*x/10), x, -5, 0 )
integrate( 5*sin(n*%pi*x/10), x, 0, 5 ) ),
ratsimp(%%) );
%pi n
10 cos(-----) - 10
2
(%o7)
- -----------------%pi n
(%i8) define( b(n), bn );
%pi n
10 cos(-----) - 10
2
(%o8)
b(n) := - -----------------%pi n
(%i9) map(b,makelist(i,i,1,7));
10
10
10
2
10
10
(%o9)
[---, ---, -----, 0, ---, -----, -----]
%pi %pi 3 %pi
%pi 3 %pi 7 %pi
(%i10) fs(nmax) := sum( b(m)*sin(m*%pi*x/10), m, 1, nmax )$
(%i11) map(fs,[1,2,3]);
%pi x
%pi x
%pi x
10 sin(-----) 10 sin(-----)
10 sin(-----)
10
5
10
(%o11) [-------------, ------------- + -------------,
%pi
%pi
%pi
3 %pi x
%pi x
10 sin(-------)
10 sin(-----)
10
5
--------------- + ------------3 %pi
%pi
(%i12) qdraw( xr(-15, 15), yr(-10, 10),
ex( [f(x), fs(1), fs(2) ], x, -10,
+
);
+
%pi x
10 sin(-----)
10
+ -------------]
%pi
10 ) )$
The plot of f(x) with the two lowest approximations looks like
10
1
2
3
-5
-10
-15
-10
-5
10
14
15
10
1
2
-5
-10
-15
-10
-5
10
15
-5
-10
-10
-5
10
15
20
25
30
15
2inx
exp
(n = 0, 1, 2, )
(10.8)
ba
on the interval (a, b). Define the function n (x) as
n (x) = exp
2 i n x
.
ba
(10.9)
n (x) n (x) = 1.
(10.10)
b
a
n (x) m (x) dx = (b a) n m ,
(10.11)
n m =
1 for n = m
0 for n 6= m.
(10.12)
Eq.(10.11) is clearly true for n = m, using Eq.(10.10). For m 6= n, we can simplify this integral by using the exponential product law eA eB = eA+B , letting r = m n 6= 0, and changing the variable of integration x y via x = (b a) y + a. The resulting integral in terms of y will then be over the interval
(0, 1). The differential dx (b a) dy and (b a) comes outside the integral. Also, inside the exponential,
x/(b a) a/(b
the integral
R 1 a) + y, and we can take outside an exponential function of a constant. Thus
r
is proportional to 0 exp(2 i r y) dy, which is proportional to exp(2 i r) 1 = exp(2 i) 1 = 0.
We now write some function of x as a linear combination of the n (x) with coefficients Cn to be determined.
f (x) =
Cn n (x).
(10.13)
n=
To find the {Cn }, we multiply both sides of Eq.(10.13) by m (x) dx, integrate both sides over the interval
(a, b), and use orthogonality, Eq.(10.11).
Z
b
a
f (x) m (x) dx =
=
X
n=
Cn
a
Cn (b a) n m
n=
= (b a) Cm .
16
n (x) m (x) dx
b
a
(10.14)
Cn n (x)
n=
Z b
2 i n x
1
2iny
=
exp
f (y) exp
dy
b
a
b
a
b
a
a
Z
1 X b
2 i n (y x)
dy.
=
f (y) exp
b a a
ba
We now separate out the n = 0 term and combine the n = m terms into a sum over the positive integers.
Z b
Z
1
1 X b
2 i n (y x)
2 i n (y x)
f (x) =
+ exp
dy
f (y) dy +
f (y) exp
ba a
b a n=1 a
ba
ba
Z b
Z
1
2 X b
2 n (y x)
=
f (y) dy +
f (y) cos
dy
ba a
b a n=1 a
ba
Using the trig identity cos(A B) = cosA cosB + sinA sinB, we recover the trigonometric form of the
Fourier series expansion of a function over the interval (a, b), which will represent a function which has period
equal to (b - a) for all values of x.
X
2nx
2nx
1
f (x) = a0 +
an cos
+ bn sin
(10.15)
2
ba
ba
n=1
The coefficients are given by the integrals
Z b
2ny
2
f (y) cos
dy,
an =
ba a
ba
2
bn =
ba
f (y) sin
a
2ny
ba
dy.
(10.16)
f (y) +
(10.17)
X
nx
1
nx
an cos
f (x) = a0 +
+ bn sin
(10.18)
2
p
p
n=1
with coefficients
1
an =
p
f (y) cos
p
ny
p
1
bn =
p
dy,
17
f (y) sin
p
ny
p
dy.
(10.19)
X
1
[an cos(n x) + bn sin(n x)]
f (x) = a0 +
2
n=1
with coefficients
1
an =
1
bn =
(10.20)
(10.21)
(10.23)
The two equations (10.22) and (10.23) are an example of a Fourier transform pair, which include conventions
about where to place the factor of 2/.
Here is a simple example. We let the function be f (x) = sin(x) ex , defined for x 0. Let the letter w be
used to stand for . We first calculate the Fourier cosine transform FC (f , ) (we use the symbol fcw in our
work here) using integrate and then show that the inverse integral over gives back the original function.
(%i1) f:sin(x)*exp(-x)$
(%i2) integrate(f*cos(w*x),x,0,inf);
(%o2)
2
2
2 w
------ - -------4
4
w + 4
2 w + 8
2
2 (w - 2)
(%o3)
- -----------4
%pi (w + 4)
(%i4) integrate(fcw*cos(w*x),w,0,inf);
Is x positive, negative, or zero?
p;
- x
(%o4)
%e
sin(x)
18
We can also use the package fourie.mac, which we explored in the section on Fourier series. This package
provides for the calculation of our Fourier cosine transform integral via the fourintcos(expr,var) function.
The function fourintcos(f,x) returns an answer with the label az which contains the Fourier cosine integral
FC (f , z), with the letter z being the package convention for what we called w (),
(%i5) load(fourie);
(%o5) C:/PROGRA1/MAXIMA3.1/share/maxima/5.18.1/share/calculus/fourie.mac
(%i6) fourintcos(f,x);
2
2
z
2 (------ - ------)
4
4
z + 4
z + 4
(%t6)
a = ------------------z
%pi
(%o6)
(%i7) az : ratsimp(rhs(%t6));
[%t6]
2
2 z - 4
(%o7)
- -------------4
%pi z + 4 %pi
(%i8) (2/%pi)*ratsimp(%pi*az/2);
2
2 (z - 2)
(%o8)
- -----------4
%pi (z + 4)
Thus fourintcos(expr,var) agrees with our definition of the Fourier cosine transform.
10.3.2 Fourier Sine Integrals and fourintsin(..)
Given some function f (x) defined for x 0, we define the Fourier sine transform of this function as
Z
2
FS (f , ) =
sin( x) f (x) dx
(10.24)
0
The given function f (x) can then be written as an integral over positive values of :
Z
f (x) =
FS (f , ) sin( x) d
(10.25)
The two equations (10.24) and (10.25) are another Fourier transform pair, which include conventions about
where to place the factor of 2/.
19
Here is a simple example. We let the function be f (x) = cos(x) ex , defined for x 0. Let the letter w stand
for . We first calculate the Fourier sine transform FS (f , ) (we use the symbol fsw in our work here) using
integrate and then show that the inverse integral over gives back the original function.
(%i1) f:cos(x)*exp(-x)$
(%i2) assume(w>0)$
(%i3) integrate(f*sin(w*x),x,0,inf);
3
w
-----4
w + 4
(%o3)
3
2 w
(%o4)
-----------4
%pi (w + 4)
(%i5) integrate(fsw*sin(w*x),w,0,inf);
Is x positive, negative, or zero?
p;
(%o5)
- x
%e
cos(x)
We can also use the package fourie.mac, which we used above. This package provides for the calculation of
our Fourier sine transform integral via the fourintsin(expr,var) function. The function fourintsin(f,x) returns
an answer with the label bz which contains the Fourier sine integral FS (f , z), with the letter z being the
package convention for what we called w ().
(%i6)
(%o6)
(%i7)
(%o7)
(%i8)
(%o8)
(%i9)
load(fourie);
C:/PROGRA1/MAXIMA3.1/share/maxima/5.18.1/share/calculus/fourie.mac
facts();
[w > 0]
(forget(w>0),facts());
[]
fourintsin(f,x);
3
2 z
(%t9)
b = -----------z
4
%pi (z + 4)
(%o9)
(%i10) bz : rhs(%t9);
(%o10)
[%t9]
3
2 z
-----------4
%pi (z + 4)
Thus fourintsin(expr,var) agrees with our definition of the Fourier sine transform.
20
The two equations (10.26) and (10.27) are another Fourier transform pair, which include conventions about
where to place the factor of 2 as well as which member has the minus sign in the exponent.
If the given function is even, f (x) = f (x), then the exponential Fourier transform has the symmetry
FExp (f , ) = FExp (f , )
(10.28)
FExp (f , ) =
(10.29)
If the given function is odd, f (x) = f (x), then the exponential Fourier transform has the symmetry
FExp (f , ) = FExp (f , )
(10.30)
FExp (f , ) =
(10.31)
If the given function is neither even nor odd, the function can always be written as the sum of an even function
fe (x) and an odd function fo (x):
f (x) fe (x) + fo (x) =
1
1
(f (x) + f (x) + (f (x) f (x)
2
2
(10.32)
and can be expressed in terms of the Fourier cosine transform of fe (x) and the Fourier sine transform of fo (x):
FExp (f , ) FExp (fe + fo , ) =
1
i
FC (fe , ) + FS (fo , )
2
2
(10.33)
The fourie.mac package function fourint(expr,var) displays the non-zero coefficients az and/or the bz , in
terms of which we can write down the value of FExp (f , z) (with our conventions):
FExp (f , z) =
i
1
az + bz
2
2
(10.34)
(%i1) assume(w>0)$
(%i2) i1:integrate(exp(%i*w*x)*cos(x)*exp(x),x,minf,0);
2
3
w + 2
%i w
(%o2)
------ - -----4
4
w + 4
w + 4
(%i3) i2:integrate(exp(%i*w*x)*cos(x)*exp(-x),x,0,inf);
3
2
%i w
w + 2
(%o3)
------ + -----4
4
w + 4
w + 4
(%i4) i12:ratsimp(i1+i2);
2
2 w + 4
(%o4)
-------4
w + 4
(%i5) 2*ratsimp(i12/2);
2
2 (w + 2)
(%o5)
---------4
w + 4
(%i6) iexp:%/(2*%pi);
2
w + 2
(%o6)
-----------4
%pi (w + 4)
2 + 2
( 4 + 4)
(10.35)
We can use integrate to calculate the inverse Fourier exponential transform, recovering our original even
function of x.
(%i7) integrate(exp(-%i*w*x)*iexp,w,minf,inf);
Is x positive, negative, or zero?
p;
- x
(%o7)
%e
cos(x)
(%i8) integrate(exp(-%i*w*x)*iexp,w,minf,inf);
Is x positive, negative, or zero?
n;
x
(%o8)
%e cos(x)
22
Next we use integrate again directly to calculate the Fourier cosine transform of the given even function, now
considered as defined for x 0 and confirm that the required exponential Fourier transform in this case is
correctly given by 12 FC (f , ).
(%i9) i3:ratsimp(integrate(cos(x)*exp(-x)*cos(w*x),x,0,inf));
2
w + 2
(%o9)
-----4
w + 4
(%i10) i3:(2/%pi)*i3;
2
2 (w + 2)
(%o10)
-----------4
%pi (w + 4)
Output %o10 is the value of FC (f , ), and one half of that value is the required exponential Fourier transform.
Next we use fourint(expr,var) with this even function.
(%i1) load(fourie);
(%o1) C:/PROGRA1/MAXIMA3.1/share/maxima/5.18.1/share/calculus/fourie.mac
(%i2) fourint(cos(x)*exp(-abs(x)),x);
2
z
2
2 (------ + ------)
4
4
z + 4
z + 4
(%t2)
a = ------------------z
%pi
(%t3)
(%o3)
(%i4) ratsimp(rhs(%t2));
(%o4)
(%i5) (2/%pi)*ratsimp(%pi*%/2);
(%o5)
b = 0
z
[%t2, %t3]
2
2 z + 4
-------------4
%pi z + 4 %pi
2
2 (z + 2)
-----------4
%pi (z + 4)
which confirms that for an even function, the required exponential Fourier transform is correctly given (using
fourint) by FExp (f , z) = az /2.
23
2i
( 4 + 4)
(10.36)
We can use integrate to calculate the inverse Fourier exponential transform, recovering our original odd function of x.
(%i6) integrate(exp(-%i*w*x)*iexp,w,minf,inf);
Is x positive, negative, or zero?
p;
- x
(%o6)
%e
sin(x)
(%i7) integrate(exp(-%i*w*x)*iexp,w,minf,inf);
Is x positive, negative, or zero?
n;
x
(%o7)
%e sin(x)
(%i8) facts();
(%o8)
[w > 0]
24
Next we use integrate again directly to calculate the Fourier sine transform of the given odd function, now
considered as defined for x 0 and confirm that the required exponential Fourier transform in this case is
correctly given by 2i FS (f , ).
(%i9) ratsimp(integrate(sin(x)*exp(-x)*sin(w*x),x,0,inf));
2 w
(%o9)
-----4
w + 4
(%i10) (2/%pi)*%;
4 w
(%o10)
-----------4
%pi (w + 4)
Output %o10 is the value of FS (f , ), and multiplying by i/2 yields the required exponential Fourier transform.
Next we use fourint(expr,var) with this odd function.
(%i11) load(fourie);
(%o11) C:/PROGRA1/MAXIMA3.1/share/maxima/5.18.1/share/calculus/fourie.mac
(%i12) fourint(sin(x)*exp(-abs(x)),x);
(%t12)
a = 0
z
(%t13)
(%o13)
4 z
b = -----------z
4
%pi (z + 4)
[%t12, %t13]
which confirms that for an odd function, the required exponential Fourier transform is correctly given (using
fourint) by FExp (f , z) = (i bz )/2.
25
26
As an exercise in the manipulation of trigonometric functions, we now go back and forth between the coefficient
of %e(-x) in this result and our starting function (for positive x).
(%i8) cos(x-1)2;
(%o8)
(%i9) trigreduce(%);
(%o9)
2
cos (x - 1)
cos(2 (x - 1)) + 1
-----------------2
(%i10) ratsimp(%);
(%o10)
cos(2 x - 2) + 1
---------------2
(%i11) trigexpand(%);
(%o11)
which gets us from the original coefficient to that returned by our inverse transform integral. Now we go in the
opposite direction:
(%i12) trigreduce(%);
(%o12)
cos(2 x - 2) + 1
---------------2
(%i13) factor(%);
(%o13)
cos(2 (x - 1)) + 1
-----------------2
(%i14) trigexpand(%);
(%o14)
2
2
- sin (x - 1) + cos (x - 1) + 1
------------------------------2
(%i15) trigsimp(%);
(%o15)
2
cos (x - 1)
which returns us from the transform integral coefficient to our original coefficient. Hence we have verified the
correctness of the exponential Fourier transform for this case.
27
Next we use fourint(expr,var) with this function which is neither even nor odd.
(%i16) load(fourie);
(%o16) C:/PROGRA1/MAXIMA3.1/share/maxima/5.18.1/share/calculus/fourie.mac
(%i17) fourint(cos(x-1)2*exp(-abs(x)),x);
4
2
(cos(2) + 1) z + (6 cos(2) - 6) z + 5 cos(2) + 25
(%t17)
a = --------------------------------------------------z
6
4
2
%pi (z - 5 z + 19 z + 25)
(%t18)
4 sin(2) z
= -------------------z
4
2
%pi (z - 6 z + 25)
(%o18)
(%i19) az : rhs(%t17);
(%o19)
(%i20)
(%o20)
(%i21)
(%o21)
[%t17, %t18]
4
2
(cos(2) + 1) z + (6 cos(2) - 6) z + 5 cos(2) + 25
--------------------------------------------------6
4
2
%pi (z - 5 z + 19 z + 25)
bz : rhs(%t18);
4 sin(2) z
-------------------4
2
%pi (z - 6 z + 25)
iexp_f : az/2 + %i*bz/2;
4
2
(cos(2) + 1) z + (6 cos(2) - 6) z + 5 cos(2) + 25
--------------------------------------------------6
4
2
2 %pi (z - 5 z + 19 z + 25)
2 %i sin(2) z
+ -------------------4
2
%pi (z - 6 z + 25)
which shows that, except for notation, the results are the same. We have confirmed that for a general function,
the required exponential Fourier transform is correctly given (using fourint) by FExp (f , z) = az /2 + (i bz )/2.
10.3.7 Dirac Delta Function (x)
It is conventional to define the Dirac delta function (unit impulse function) (x) by
(10.37)
(10.38)
(x) dx = 1
a
28
for
a, b > 0
(10.39)
(y x) = (x y)
(10.40)
f (y) (y x) dy = f (x)
(10.41)
for any well behaved function f (x) (we are more careful below), provided the range of integration includes the
point x. For since (y x) is zero except at the single point y = x, we canRevaluate f (y) at that single point
and take the result outside the integral. The resulting integral
which is left is (y x) dy, and the change of
R
variables y t = y x for fixed x yields the integral (t) dt = 1.
Now let c be a positive constant (independent of the integration variable x). In the integral
change variables, x y = c x so dx = dy/c.
Z b
Z
1 cb
1
(c x) dx =
(y) dy =
c c a
c
a
Rb
a
(c x) dx, we
(10.42)
(10.43)
(10.44)
or simply (with the understanding that this kind of relation only makes sense inside an integral)
(c x) =
(x)
|c|
(10.45)
We can find a sometimes useful representation of the Dirac delta function by using the exponential Fourier
transform pair Eqs.(10.26) and (10.27). If we use y as the (dummy) variable of integration in Eq.(10.26), and
insert into Eq.(10.27), we get (interchanging the order of integration)
Z
Z
1
iy
f (x) =
e
f (y) dy ei x d
2
1
i (yx)
=
f (y)
e
d dy
2
Z
=
f (y) (y x) dy
1
(x) =
2
ei x d
(10.46)
One use of such a representation of the one dimensional Dirac delta function is to derive in a different way the
result of Eq.(10.45). From Eq.(10.46) we have
Z
1
ei c x d
(10.47)
(c x) =
2
29
Again, suppose c is a constant and c > 0. Then if we change variables y = c, we have d = dy/c.
When = , y = . When = , y = . Hence
Z
1
1
1
iyx
(c x) =
e
dy = (x)
(10.48)
c 2
c
If, on the other hand, c < 0, c = |c| in Eq.(10.47), and we make the same change of variables, when
= , y = , and when = , y = . Hence, for this case,
Z
Z
1
1
1
1
1
iyx
iyx
(c x) =
e
dy =
e
dy =
(x).
(10.49)
c 2
c
2
|c|
Combining the two cases leads us again to Eq.(10.45).
Although the representation Eq.(10.46) can be useful for formal properties of the Dirac delta function, for
actual calculation of integrals one is safer using a limiting form of that result, or even simpler versions, as we
will see. If we replace the infinite limits in Eq.(10.46) by finite limits, we can work with the representation
(x) = lim dL (x)
(10.50)
where
1
dL (x) =
2
ei x y dy =
sin(x L)
x
(10.51)
(10.52)
However, this will only be useful if the resulting integrals can be done.
An easier approach to the careful use of the Dirac delta function for the calculation of integrals is to create a
mathematically simple model of a function of x which has the required properties and whose use will result
in integrals which can easily be done. Mathematically rigorous treatments (see the Theory of Distributions) of
the Dirac delta function justify the use of such models .
Here we follow the approach of William E. Boyce and Richard C. DiPrima, in their textbook Elementary Differential Equations and Boundary Value Problems, Fifth Edition, John Wiley & Sons, Inc, New York, 1992,
Section 6.5, Impulse Functions.
Let
d (x) =
(10.53)
which defines a rectangular pulse with base length 2 , height 1/(2 ) with area under the curve equal to 1.
This is an even function of x centered on x = 0 which gets narrower and taller as 0.
Then
d (y x) =
30
(10.54)
This model can then be used in the form (with the range of integration assumed to include the point y = x):
Z
Z
Z x+
1
f (y) (y x) dy = lim f (y) d (y x) dy = lim
f (y) dy.
(10.55)
0
0 2 x
The integral should be done before taking the limits in this safer approach.
However, if f (y) is a continuous function and possesses a derivative in a complete neighborhood of x, we can
use the mean value theorem of calculus to write this limit as
1
f (
y) (2 ) = lim f (
y)).
0 2
0
lim
(10.56)
where (x ) < y
< (x + ) As 0, y
x, and f (
y) f (x), which recovers Eq. (10.41), and which
we repeat here for emphasis.
Z
f (y) (y x) dy = f (x)
(10.57)
for any function f (x) which is continuous and possesses a derivative in a complete neighborhood of x, provided
the range of integration includes the point x.
10.3.8 Laplace Transform of the Delta Function Using a Limit Method
Use of Eq.
R (10.57) allows us to immediately write down the Laplace transform of (t t0 ) for t0 > 0, the
integral 0 es t (t t0 ) dt, since the function es t which multiplies the delta function is continuous and
possesses a derivative for all values of t.
However, as a consistency check, lets also use the limit method just discussed to derive this result.
Z
L{(t t0 )}
es t (t t0 ) dt = es t0
(10.58)
As a bonus, the limit of Eq.(10.58) as t0 0+ then gives us the Laplace transform of (t).
Z
L{(t)}
es t (t) dt = 1
0
31
(10.59)
(10.60)
where f (t) stands for the expr argument (here assumed to depend explicitly on t) of laplace. laplace assumes
that s is a very large positive number. If there are convergence issues of the integral, one allows s to be a
complex number s = x + i y and the assumption is made that the integral converges to the right of some line
Re(s) = const in the complex s plane.
L{t} = 1/s2
(%i5) laplace(t,t,s);
(%o5)
1
-2
s
(%i6) specint(exp(-s*t)*t,t);
(%o6)
1
-2
s
(%i7) ilt(%,s,t);
(%o7)
32
L{ea t } = 1/(s a)
(%i8) laplace(exp(a*t),t,s);
(%o8)
(%i9) specint(exp(-s*t)*exp(a*t),t);
(%o9)
1
----s - a
1
----s - a
1
------2
2
s + a
(%i11) (specint(exp(-s*t)*sin(a*t)/a,t),ratsimp(%%) );
1
(%o11)
------2
2
s + a
(%o10)
s
------2
2
s + a
(%i13) (specint(exp(-s*t)*cos(a*t),t ), ratsimp(%%) );
s
(%o13)
------2
2
s + a
(%o12)
(%i15)
(%o15)
(%i16)
(%o16)
s
---------2
2 2
(s + a )
(specint(exp(-s*t)*sin(a*t)*t/(2*a),t ),ratsimp(%%) );
s
----------------4
2 2
4
s + 2 a s + a
map(factorsum,%);
s
---------2
2 2
(s + a )
33
We find in the above example that ilt cannot find the inverse Laplace transform.
34
L{erf ( t)} = ( s s + 1 )1
Here again ilt fails.
(%i25) assume(s>0)$
(%i26) laplace(erf(sqrt(t)),t,s);
(%o26)
(%i27)
(%o27)
(%i28)
(%o28)
(%i29)
(%o29)
1
------------s sqrt(s + 1)
specint(exp(-s*t)*erf(sqrt(t)),t);
1
---------------1
3/2
sqrt(- + 1) s
s
radcan(%);
1
------------s sqrt(s + 1)
ilt(%,s,t);
1
ilt(-------------, s, t)
s sqrt(s + 1)
2 /4
L{erf (t)} = es
(1 erf (s/2)) s1
(%o30)
2
s
-4
s
%e
(1 - erf(-))
2
----------------s
(%i31) ilt(%,s,t);
2
s
-4
s
%e
(1 - erf(-))
2
(%o31)
ilt(-----------------, s, t)
s
(%i32) specint(exp(-s*t)*erf(t),t);
- s t
(%o32)
specint(%e
erf(t), t)
35
10.4.3 Use of the Dirac Delta Function (Unit Impulse Function) delta with laplace(..)
The laplace function recognises delta(arg) as part of the expression supplied to laplace. We have introduced
the Dirac delta function (unit impulse function) in Sections 10.3.7 and 10.3.8. Here are three examples of using
delta with laplace.
L{(t)} = 1
(%i1) laplace(delta(t),t,s);
(%o1)
(%i2) ilt(1,s,t);
(%o2)
1
ilt(1, s, t)
L{(t a)} = ea s
(for a > 0):
(%i3) laplace(delta(t-a),t,s);
Is a positive, negative, or zero?
p;
- a s
(%o3)
%e
- a s
sin(a b) %e
(10.61)
36
For advanced work, one can use the general formula for the inverse Laplace transform
Z +i
1
f (t > 0) =
es t F(s) ds
2 i i
(10.62)
where the contour of integration is a vertical line in the complex s = x + i y plane (ie., along a line x = ), to
the right of all singularities (poles, branch points, and essential singularities) of the integrand. Here we assume
the only type of singularities we need to worry about are poles, isolated values of s where the approximate
power series expansion for s near sj is g(sj )/(s sj )m , where g(sj ) is a finite number, and m is the order of
the pole. If m = 1, we call it a simple pole. At a particular point (x, y) of the contour, the exponential factor
has the form es t = ei t y et x . Because t > 0 the integrand is heavily damped by the factor ex t when x ,
and the contour of integration can be turned into a closed contour by adding a zero contribution which is the
integral of the same integrand along a large arc in the left hand s plane (in the limit that the radius of the arc
approaches ), and the resulting closed contour integral can then be evaluated using the residue theorem of
complex variable theory. The (counter-clockwise) closed contour integral is then given by 2 i times the sum
of the residues of the integrand at the isolated poles enclosed by the contour.
The factor 2 i coming from the integral part of Eq.(10.62) is then cancelled by the factor 1/(2 i) which
appears in the definition (Eq.(10.62)) of the inverse Laplace transform, and one has the simple result that the
inverse Laplace transform is the sum of the residues of the poles of the integrand.
10.5.2 residue: Residues at Poles
We can use the Maxima residue function to illustrate how the sum of the residues at all the poles of the
integrand reproduces the answer returned by ilt.
residue (expr, z, z_0)
Computes the residue in the complex plane of the expression expr when the variable z assumes
the value z_0. The residue is the coefficient of (z - z_0)(-1) in the Laurent series for
expr.
(%i1) residue (s/(s2+a2), s, a*%i);
(%o1)
(%i2) residue (sin(a*x)/x4, x, 0);
(%o2)
1
2
3
a
- -6
We start with some arbitrary rational algebraic function of s, use ilt to determine the corresponding function
of t, and then compute the inverse Laplace transform (a second way) by summing the values of the residues of
the Laplace inversion integrand in the complex s plane.
(%i3) fs : -s/(s3 +4*s2 + 5*s +2)$
(%i4) ft : ( ilt(fs,s,t),collectterms(%%,exp(-t),exp(-2*t) ) );
- t
- 2 t
(%o4)
(t - 2) %e
+ 2 %e
37
(%i6) fs - %;
(%o6)
(%i7) fst : exp(s*t)*fs;
(%o7)
s
- ------------------3
2
s + 4 s + 5 s + 2
0
s t
s %e
- ------------------3
2
s + 4 s + 5 s + 2
(%i8) partfrac(fst,s);
(%o8)
s t
s t
s t
2 %e
2 %e
%e
------- - ------- + -------s + 2
s + 1
2
(s + 1)
The inverse Laplace transform integrand above was called fst, and we used partfrac on fst to exhibit the poles
of this integrand. We see that there is one simple pole at s = 2 and one pole of order 2 located at s = 1.
To use the Maxima function residue, we need to tell Maxima that t > 0.
(%i9) assume( t > 0 )$
(%i10) r1 : residue(fst,s,-2);
- 2 t
(%o10)
(%i11) r2 : residue(fst,s,-1);
2 %e
- t
(%o11)
(%i12) r1 + r2 - ft;
(%o12)
(t - 2) %e
0
which shows that the sum of the residues reproduces the function of t which ilt produced.
This concludes our discussion of the inverse Laplace transform.
38
Preface
COPYING AND DISTRIBUTION POLICY
This document is part of a series of notes titled
"Maxima by Example" and is made available
via the authors webpage http://www.csulb.edu/woollett/
to aid new users of the Maxima computer algebra system.
NON-PROFIT PRINTING AND DISTRIBUTION IS PERMITTED.
You may make copies of this document and distribute them
to others as long as you charge no more than the costs of printing.
These notes (with some modifications) will be published in book form
eventually via Lulu.com in an arrangement which will continue
to allow unlimited free download of the pdf files as well as the option
of ordering a low cost paperbound version of these notes.
Feedback from readers is the best way for this series of notes to become more helpful to new users of Maxima. All
comments and suggestions for improvements will be appreciated and carefully considered.
LOADING FILES
The defaults allow you to use the brief version load(fft) to load in the
Maxima file fft.lisp.
To load in your own file, such as qfft.mac (used in this chapter),
using the brief version load(qfft), you either need to place
qfft.mac in one of the folders Maxima searches by default, or
else put a line like:
file_search_maxima : append(["c:/work3/###.{mac,mc}"],file_search_maxima )$
in your personal startup file maxima-init.mac (see Ch. 1, Introduction
to Maxima for more information about this).
Otherwise you need to provide a complete path in double quotes,
as in load("c:/work3/qfft.mac"),
We always use the brief load version in our examples, which are generated
using the Xmaxima graphics interface on a Windows XP computer, and copied
into a fancy verbatim environment in a latex file which uses the fancyvrb
and color packages.
11.1 Examples of the Use of the Fast Fourier Transform Functions fft and inverse fft
We discuss the use of Maximas fast Fourier transform package fft.lisp, which has been rewritten (effective with
version 5.19) to allow list input and output (rather than being restricted to array input and output).
We first present five simple examples of using Maximas fast Fourier transform functions fft and inverse fft. We then
discuss our notation and the utility functions available in the Ch.11 file qfft.mac. We then present a derivation of the
discrete Fourier transformation pairs, using Maximas conventions.
11.1.1 Example 1: FFT Spectrum of a Monochromatic Signal
We load in the Maxima package fft.lisp and also our own package qfft.mac.
(%i1) load(fft);
(%o1) C:/PROGRA1/MA89DF1.0/share/maxima/5.19.0/share/numeric/fft.lisp
(%i2) load(qfft);
(%o2)
c:/work3/qfft.mac
Our first example uses the simplest possible signal which still contains some information, a signal having one intrinsic
frequency. We assume the signal is F(t) = cos(6 t). This signal has an angular frequency = 6 = 2 f where f
is the frequency in Hertz (ie., in sec1 ). Thus the frequency f = 3 sec1 . We bind the symbol e to this signal expression
for later use:
(%i3) e : cos ( 6*%pi*t )$
Let ns be the (even) number of function samples, and fs be the sampling frequency.
The qfft package function nyquist(ns, fs) computes the time interval between signal samples dt = 1/fs, the Nyquist
integer knyq = ns/2, the frequency resolution df = fs/ns, and the Nyquist frequency
fnyq = knyq * df = fs/2.
The product of the time interval dt between samples of the signal and the frequency resolution df is always the inverse
of the total number of signal samples ns:
dt * df = 1 / ns
We select fs and ns to satisfy two conditions. The only intrinsic frequency of the signal is f0 = 3 s1 . First we need
fs > 2 f0 which means that fs > 6 s1 . Secondly we need the frequency resolution df to satisfy df < f0, which will be
satisfied if we choose df such that f0 = 3 df , or df = 1 hertz. But then df = fs / ns = 1, or fs = ns, so
the first condition becomes ns > 6, but we also need ns to be an even number of the form 2m for some integer m, so we
choose ns = 8.
We then bind both ns and fs to the value 8 and assign dt (the sampling interval) to the first element of the list produced
by the package function nyquist( ns, fs ), which also prints out dt, knyq, fnyq, and df.
(%i4) ( ns : 8, fs : 8 )$
(%i5) dt : first (nyquist (ns,fs));
sampling interval dt = 0.125
Nyquist integer knyq = 4
Nyquist freq fnyq = 4.0
freq resolution df = 1.0
(%o5)
0.125
4
We then use the package function sample(expr, var, ns, dvar) to generate a list of floating point numbers as
the expression expr is evaluated ns times, generating the list (with dvar being the time step dt here)
[F(0),F(dt),F(2*dt),...,F((ns-1)*dt )] holding the values F(m*dt), for m = 0,1,2,...,ns-1. More
details of the syntax of the qfft.mac package functions can be found in Section 11.3. Recall that we have just bound
ns and dt to numerical values and that the expression e depends on the variable t.
(%i6) flist : sample (e,t,ns,dt);
(%o6) [1.0, - 0.707, - 1.83691E-16, 0.707, - 1.0, 0.707, 5.51073E-16, - 0.707]
We see that elements three, F(2*dt), and seven, F(6*dt), are tiny numbers of the order of the default floating
point errors, and are numerically equivalent to zero.
We first make a plot of both the given function (the signal) and a list of points [m*dt, F(m*dt)] constructed using
the package function vf (flist, dt). Recall that the signal is first sampled at t = 0.
(%i7) tflist : vf (flist,dt);
(%o7) [[0, 1.0], [0.125, - 0.707], [0.25, - 1.83691E-16], [0.375, 0.707],
[0.5, - 1.0], [0.625, 0.707], [0.75, 5.51073E-16], [0.875, - 0.707]]
We let tmax be the sampling time, the number of signal samples times the time interval between samples.
(%i8) tmax : ns*dt;
(%o8)
1.0
(%i9) plot2d([e ,[discrete,tflist]], [t,0,tmax],
[style,[lines,3],[points,3,2,1]],
[legend,false])$
0.5
-0.5
-1
0
0.2
0.4
0.6
t
0.8
5
Now that we have looked at both the signal and sample signal values (on the same plot), we next look at the fast Fourier
frequency spectrum implied by this single frequency signal sample. We first define glist to be the fast fourier transform of flist
(%i10) glist : fft (flist);
(%o10) [- 2.34662E-17, 1.11022E-16 - 3.30546E-17 %i,
1.52656E-16 %i - 4.59227E-17, 0.5 - 1.18171E-16 %i, 1.15312E-16,
2.16746E-16 %i + 0.5, - 1.52656E-16 %i - 4.59227E-17,
5.55112E-17 - 6.55197E-17 %i]
(%i11) fchop (%);
(%o11)
[0.0, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0]
in which we have used Maximas fast fourier transform function fft. We then used our package function fchop to set
tiny floating point numbers to zero. The qfft package function current_small() prints out the current setting of the
qfft.mac parameter _small% used by fchop.
(%i12) current_small()$
current default small chop value =
1.0E-13
The first element of glist corresponds to k = 0, and the list glist contains the values of the fast Fourier transform amplitudes
G(k*df) for k = 0, 1, 2, ..., ns -1, where df is the frequency resolution (for this example, df = 1 hertz). We
call the value G(k*df) the fast Fourier transform amplitude corresponding to the frequency f = k*df.
If we look at the chopped version, we see that the first non-zero fast fourier transform amplitude occurs at element four, which
corresponds to k = 3, which corresponds to the frequency f = k*df = 3 * 1 = 3 hertz. In a later section exploring the
basic ideas of the fast Fourier transform, we explain why all the usable spectrum information is contained in the interval k = 0 to
k = knyq = 4.
To make a simple point plot of the fourier amplitudes, we first use the package function kg to make a list of the points [k, G(k*df)]
out to the Nyquist integer knyq. Since we want real numbers for a plot, this function takes the absolute value of each Fourier amplitude and also chops tiny numbers.
(%i13) kglist : kg (glist);
(%o13)
[[0, 0.0], [1, 0.0], [2, 0.0], [3, 0.5], [4, 0.0]]
(%i14) plot2d ( [discrete, kglist],[x,0,5],[y,0,0.8],
[style,[points,5,1,1]],[xlabel,"k"],
[ylabel," "],[gnuplot_preamble,"set grid;"])$
3
k
6
We can also use plot2d to make a simple histogram, using kglist.
(%i15) vbars : makelist ( [discrete,
[[kglist[i][1],0],[kglist[i][1],kglist[i][2]]]] ,
i,1,length(kglist) );
(%o15) [[discrete, [[0, 0], [0, 0.0]]], [discrete, [[1, 0], [1, 0.0]]],
[discrete, [[2, 0], [2, 0.0]]], [discrete, [[3, 0], [3, 0.5]]],
[discrete, [[4, 0], [4, 0.0]]]]
(%i16) plot2d ( vbars,[y,0,0.8],[style,[lines,5,1]],
[ylabel," "],[xlabel," k "],[legend,false],
[gnuplot_preamble,"set grid;"] )$
0.5
1.5
2
k
2.5
3.5
7
The entry
(%i17) spectrum (glist, 5, 0.8 )$
0.5
1.5
2
k
2.5
3.5
We see that inverse fft (glist) recovers our original signal sample list flist to within floating point errors.
8
11.1.2 Example 2: FFT Spectrum of a Sum of Two Monochromatic Signals
Almost all signals will contain more than one intrinsic frequency, and to recover a portion of the frequency spectrum with
fidelity, we need to satisfy the two conditions
fs > 2 fhigh
and df flow ,
(11.1)
in which flow is the lowest intrinsic frequency to be identified, and fhigh is the highest intrinsic frequency to be identified.
(Again, fs is the sampling frequency, and df is the frequency resolution).
We assume now that the signal is F(t) = cos(2 t) + sin(4 t). We thus have a signal with the frequencies f1 = 1 s1
and f2 = 2 s1 . With fs being the sampling frequency, and ns being the number of signal samples, we require fs > 2 fhigh = 4, as
well as df flow = 1. If we choose flow = 3 df , then df = 1/3 = fs/ns, or fs = ns/3. So the first condtion then implies
we need ns/3 > 4, or ns > 12. Since ns also should be equal to 2m for some integer m, we choose ns = 16. Then fs = 16/3
and df = fs/ns = 1/3 hertz.
(%i1) ( load(fft), load(qfft) )$
(%i2) e : cos(2*%pi*t) + sin(4*%pi*t)$
(%i3) (ns : 16, fs : 16/3)$
(%i4) dt : first (nyquist (ns,fs));
sampling interval dt = 0.188
Nyquist integer knyq = 8
Nyquist freq fnyq = 2.6667
freq resolution df = 0.333
(%o4)
0.188
(%i5) flist : sample (e,t,ns,dt)$
(%i6) %,fll;
(%o6)
[1.0, - 0.324, 16]
(%i7) tmax: ns*dt;
(%o7)
3.0
(%i8) tflist : vf (flist,dt)$
(%i9) %,fll;
(%o9)
[[0, 1.0], [2.8125, - 0.324], 16]
(%i10) plot2d([e ,[discrete,tflist]], [t,0,tmax],
[style,[lines,3],[points,3,2,1]],
[legend,false])$
We have used our utility function fll described in the preface, which returns the first and last element of a list, as well as the length
of the list. The plot thus produced is
2
1.5
1
0.5
0
-0.5
-1
-1.5
-2
0
0.5
1.5
t
2.5
9
We next generate the list glist of fast Fourier transform amplitudes G(k*df) and use spectrum to look at the implied
frequency spectrum.
(%i11) glist : fft (flist)$
(%i12) %,fll;
(%o12)
[- 7.94822E-17, 1.52656E-16 - 5.7151E-17 %i, 16]
(%i13) spectrum (glist,5,0.6)$
0.6
0.5
0.4
0.3
0.2
0.1
0
0
4
k
10
11.1.3 Example 3: FFT Spectrum of a Rectangular Wave
A rectangular wave as a function of time t with period equal to 64 sec which cycles between plus and minus 1 can be
constructed from floor and mod in the form: rwave(t) := 2*mod(floor(t/32),2) - 1.
For t = 0, t/32 = 0, floor(t/32) = floor(0) = 0, mod(0,2) = 0, so rwave(0) = -1.
(%i1) rwave(t):= 2*mod(floor(t/32),2) -1 $
(%i2) [floor(0),mod(0,2),rwave(0)];
(%o2)
[0, 0, - 1]
Hence rwave(0 + 64) = rwave(0) and rwave(t) has a period equal to 64 sec.
We first look at the rectangular wave signal with a plot.
(%i5) plot2d(rwave(t),[t,0,128],[y,-1.5,1.5],
[ylabel," "],[style,[lines,5]],
[gnuplot_preamble,"set grid;set zeroaxis lw 2;"])$
1.5
0.5
-0.5
-1
-1.5
0
20
40
60
80
100
120
11
We thus try the combination, ns = 256, and fs = 1 hertz.
(%i6) (ns:256, fs:1)$
(%i7) (load(fft),load(qfft) )$
(%i8) dt:first(nyquist(ns,fs));
sampling interval dt = 1.0
Nyquist integer knyq = 128
Nyquist freq fnyq = 0.5
freq resolution df = 0.00391
(%o8)
1.0
(%i9) flist : sample(rwave(t),t,ns,dt)$
(%i10) fll (flist);
(%o10)
[- 1.0, 1.0, 256]
(%i11) makelist (flist[i],i,1,10);
(%o11) [- 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0, - 1.0]
(%i12) tmax: ns*dt;
(%o12)
256.0
(%i13) tflist : vf (flist,dt)$
(%i14) fll (tflist);
(%o14)
[[0, - 1.0], [255.0, 1.0], 256]
(%i15) plot2d([rwave(t) ,[discrete,tflist]], [t,0,tmax],
[y,-1.5,1.5],[ylabel," "],
[style,[lines,3],[points,1,0,1]],
[legend,false])$
The sample_plot invocation produces the black points of the sample on top and bottom of the rectangular wave shown
here:
1.5
0.5
-0.5
-1
-1.5
0
50
100
150
200
250
12
Next we look at the signal frequency spectrum from k = 0 to k = knyq = 128. Since f = k*df, and df = 1/256
hertz, the low fundamental intrinsic frequency f_0 = 1/64 hertz will be located at k = 4, and the maximum possible
frequency component will be fnyq = knyq*df = 0.5 hertz = 32*f_0. The spectrum plot is generated by passing
the list flist containing ns = 256 signal samples, along with nlw = 3, and ymax = 0.7 to spectrum:
(%i16) glist : fft (flist)$
(%i17) %,fll;
(%o17)
(%i18) spectrum (glist,3,0.7)$
0.7
0.6
0.5
0.4
0.3
0.2
0.1
0
0
20
40
60
80
100
120
k
Figure 9: Spectrum from k = 0 to knyq = 128
The plot shows lines at k = 4, 12, 20, 28, 36, ..... Since f = k*df and f_0 = 4*df is the fundamental
frequency, the frequencies present are f_0, 3*f_0, 5*f_0, 7*f_0,... which is the fundamental plus odd harmonics of the fundamental. We know there must be high frequency components to account for the sharp corners of the
signal.
13
11.1.4 Example 4: FFT Spectrum Sidebands of a Tone Burst Before and After Filtering
A tone burst signal consisting of a sine wave begins at t = 0 and ends abruptly after forty five seconds. The fast Fourier
frequency spectrum of such a signal, when sampled over the duration of the sine wave plus some time following the sine
wave end, will contain sideband frequencies above and below the intrinsic frequency of the sine wave. Many signal
filters can be used to allow the easy identification of the intrinsic sine wave frequency by surpressing the sideband frequencies. We use for the tone burst the sine wave: sin(2 t/5) during the time interval 0 t 45 sec, and then abruptly
dropping to 0 for t > 45 sec. The intrinsic frequency of the sine wave is f0 = 1/5 hertz, and the corresponding
period is 5 sec, thus the sine wave lasts for nine periods. We will use the following idealized model of such a signal by
ignoring the actual time needed to end the sine wave.
(%i1) sig(t) := if t < 45 then sin(2*%pi*t/5.0)
else 0$
We will use this definition only for t 0 in our work. With fs the sampling frequency, if we want about 10 samples/cycle (ie.,
10 per 5 sec), then we want period*fs = 10, or fs roughly equal to 2 hertz. We want the intrinsic, frequency f0 (
0.2 hertz) to not be too close to the left end of the frequency spectrum plot so we can see the low frequency sidebands as well
as the higher frequency sidebands.
Suppose we try requiring that f0 = 0.2 hertz = 50*df = 50*fs/ns. Solving for the number of signal samples ns, we
get ns = 50 * 2 * 5 = 500. To get a power of 2 we choose the closest such quantity, ns = 512. We then return to our f0
location requirement to solve for the resulting value of fs to get fs = 512/250 = 2.048 hertz.
(%i2) load (qfft)$
(%i3) (ns:512,fs:2.048)$
(%i4) dt : first(nyquist(ns,fs));
sampling interval dt = 0.488
Nyquist integer knyq = 256
Nyquist freq fnyq = 1.024
freq resolution df = 0.004
(%o4)
(%i5) tmax : ns*dt;
(%o5)
0.488
250.0
We can plot a Maxima function defined with the if then else construct without problem since plot2d evaluates its arguments.
(%i6) plot2d ( sig(t),[t,0,tmax],[y,-1.5,1.5],
[style,[lines,1,0]],[ylabel," "],[nticks,100],
[legend,false],[gnuplot_preamble,"set grid;"])$
0.5
-0.5
-1
-1.5
0
50
100
150
200
250
Figure 10: Sine Wave Tone Burst, Period = 5 sec, Duration = Nine Periods
14
Using the qfft package function sample with a Maxima function defined with the if...then construct produces a list
each element of which includes if then else, which can be used with plot2d. However, we will include an extra
evaluation in defining our flist so we can see the numerical values as a list. Note that the syntax expr, fll; causes an
extra evaluation, so to be careful we need to use the syntax fll (expr).
(%i7) flist : sample (sig(t),t,ns,dt)$
(%i8) fll (flist);
(%o8) [if 0.0 < 45.0 then 0.0 else 0.0,
if 249.51 < 45.0 then - 0.576 else 0.0, 512]
(%i9) flist : ev (flist)$
(%i10) fll (flist);
(%o10)
[0.0, 0.0, 512]
(%i11) makelist(flist[i],i,1,10);
(%o11) [0.0, 0.576, 0.942, 0.964, 0.634, 0.0736, - 0.514, - 0.914, - 0.981,
- 0.69]
(%i12) tflist : vf (flist,dt)$
(%i13) fll (tflist);
(%o13)
[[0, 0.0], [249.51, 0.0], 512]
We now use plot2d to show our sample points on top of our tone burst signal (both in black).
(%i14) plot2d([sig(t) ,[discrete,tflist]], [t,0,tmax],
[y,-1.5,1.5],[ylabel," "],
[style,[lines,1,0],[points,1,0,1]],
[legend,false])$
0.5
-0.5
-1
-1.5
0
50
100
150
200
Figure 11: Signal and Sample Points Which Include 0s for t > 45 sec
250
15
We now plot the unfiltered tone burst spectrum after generating glist with fft.
(%i15)
(%i16)
(%i17)
(%o17)
(%i18)
load (fft)$
glist : fft (flist)$
fll (glist);
[- 8.08763E-5, 0.00174 - 0.00286 %i, 512]
spectrum (glist, 2, 0.1 )$
which produces the spectrum plot: We see strong sideband frequencies on both the low and high side of the intrinsic
0.1
0.08
0.06
0.04
0.02
0
0
50
100
150
200
250
k
Figure 12: Frequency Spectrum of Unfiltered Tone Burst
frequency f0 = 50*df, which is the highest peak at k = 50 (f = k*df = 50*(1/250) = 1/5 = 0.02). The sidebands
are a mathematical artifact of the finite duration of the sine wave tone burst with its abrupt beginning and end.
A windowing filter which smooths out the beginning and end of the burst envelope is used by defining a smoothed
envelope signal as the product of the unsmoothed signal and a suitable windowing function. The von Hann window
employs a sin2 pinch envelope.
(%i19) hannw(x,m) := sin(%pi*(x-1)/(m-1))2$
(%i20) sig_w(t) := hannw(t,45)*sig(t)$
(%i21) plot2d ( sig_w(t),[t,0,tmax],[y,-1.5,1.5],
[style,[lines,1,0]],[ylabel," "],[nticks,100],
[legend,false],[gnuplot_preamble,"set grid;"])$
16
which shows the filtered tone burst
1.5
0.5
-0.5
-1
-1.5
0
50
100
150
200
250
0.08
0.06
0.04
0.02
0
0
50
100
150
200
250
17
11.1.5 Example 5: Cleaning a Noisy Signal using FFT Methods
We use the same signal as used in Example 2, Sec. (11.1.2), but add some random noise to it. Without the noise, the
signal is F(t) = cos(2 t) + sin(4 t). Thus the clean signal contains the frequencies f1 = 1 s1 and f2 = 2 s1 ,
and two corresponding periods 1 = 1/f1 = 1 sec and 2 = 1/f2 = 0.5 sec. To get a noisy looking signal we have to
sample and add noise a lot of times within one or two periods of the clean signal, where we use the maximum of the
intrinsic periods. Lets try N = 512 samples over a time tmax = 2 sec. Then N t = 2 sec, so fs = 1/dt = N/2 = 256.
The first condition on the sampling frequency is that fs > 2 fhigh , or fs > 4 s1 , which is certainly satisfied. The second
condition on fs is f < flow , or df < 1 s1 , or fs/ns < 1 s1 , or fs < ns, which is also true. Hence we try ns = 512,
fs = 256.
(%i1) e : cos(2*%pi*t) + sin(4*%pi*t)$
(%i2) (load(fft), load(qfft))$
(%i3) [ns:512,fs:256]$
(%i4) dt : first(nyquist(ns,fs));
sampling interval dt = 0.00391
Nyquist integer knyq = 256
Nyquist freq fnyq = 128.0
freq resolution df = 0.5
(%o4)
0.00391
(%i5) flist : sample(e,t,ns,dt)$
(%i6) %,fll;
(%o6)
[1.0, 0.951, 512]
(%i7) flist_noise : makelist(flist[j]+0.3*(-1.0+random(2.0)),j,1,ns)$
(%i8) %,fll;
(%o8)
[1.2483, 1.0073, 512]
(%i9) tflist_noise : vf (flist_noise,dt)$
(%i10) %,fll;
(%o10)
[[0, 1.2483], [1.9961, 1.0073], 512]
(%i11) plot2d ([discrete,tflist_noise],[y,-2,2],
[style,[lines,1]],[ylabel," "])$
1.5
0.5
-0.5
-1
-1.5
-2
0
0.2
0.4
0.6
0.8
1.2
1.4
1.6
1.8
18
One way to clean this signal is to set small numbers in the fast Fourier transform to zero and inverse transform back to
the time domain using inverse fft.
In order to chop small numbers in the fast Fourier transform amplitude list, we need to produce that list, which we call
glist noise from the noisy signal sample flist noise by using fft.
(%i12) glist_noise : fft (flist_noise)$
(%i13) %,fll;
(%o13)
[- 0.0022, 5.09918E-4 %i - 0.00338, 512]
Before chopping small numbers in glist noise, we take a look at the fast Fourier frequency spectrum implied by
glist noise.
(%i14) spectrum (glist_noise,2,0.6)$
0.5
0.4
0.3
0.2
0.1
0
0
50
100
150
200
250
19
To see more clearly the dominant line region, we show another plot with the integer k in the range (0, 10):
(%i15) spectrum (glist_noise,4,0.6,0,10)$
0.5
0.4
0.3
0.2
0.1
0
0
10
0.5
0.4
0.3
0.2
0.1
0
0
50
100
150
200
250
20
Here is the cleaned spectrum in the range k = (0,10):
0.6
0.5
0.4
0.3
0.2
0.1
0
0
10
k
Figure 19: Chopped Frequency Spectrum for k in (0,10)
We now create a cleaned up signal list using inverse fft on the chopped glist, transforming back to the time domain.
(%i19)
(%i20)
(%o20)
(%i21)
(%i22)
(%o22)
Since the inverse Fourier transform will often include small imaginary parts due to floating point error, we took care
to take the real part of the returned list before looking at the cleaned up signal. We now construct the list of points [t,
F clean]:
(%i23) tflist_clean : vf ( flist_clean, dt )$
(%i24) %,fll;
(%o24)
[[0, 1.0016], [1.9961, 0.952], 512]
21
and plot first just the cleaned up signal points
(%i25) plot2d ([discrete,tflist_clean],[y,-2,2],
[style,[lines,1]],[ylabel," "])$
which produces
2
1.5
0.5
-0.5
-1
-1.5
-2
0
0.2
0.4
0.6
0.8
1.2
1.4
1.6
1.8
0.5
1
t
1.5
22
11.2 Our Notation for the Discrete Fourier Transform and its Inverse
Given a real valued signal F(t) which is to be sampled N times at the moments (separated by equal time intervals t)
t = 0, t, 2 t, ..., (N 1) t, one needs to select the two parameters N = 2m and fs , where the latter is called the
sampling frequency. The sampling time interval is then given by
1
fs
t =
(11.2)
(or else use the data determined value of t to calculate fs ). Note that the fast fourier transform algorithm used by Maxima
assumes that the number of signal samples N is some integral power of 2, N = 4, 8, 16, 32, 64, ... so an experimental
sample might have to be padded with zeroes to achieve this condition on N. The sampling frequency fs should be greater
than twice the highest frequency component to be identified in the signal and the frequency resolution f should be
smaller than the lowest frequency to be identified in the signal. Given the sampling frequency fs and the number of signal
samples N, the frequency resolution f is given by
f =
fs
N
(11.3)
We will motivate this definition below. Assuming this definition, we then require that
fs
< flow
N
(11.4)
(11.5)
A convenient choice which automatically satisfies the low frequency part of these conditions is to arrange that
flow = n f ,
(11.6)
where n = 3 or 4, say. Then that choice determines the frequency resolution to be used f = flow /n, and from the
definition of f , Eq.(11.3), this requires that
fs = N flow /n
(11.7)
and then Eq.(11.5) implies the condition on N:
N>
2 n fhigh
flow
(11.8)
(11.9)
N > 2 n,
(11.10)
fs = N
Eq.(11.5) becomes
and
f0
(11.11)
n
In Example 1, the signal frequency is f0 = 3, and we chose n = 3. Then, Eq.(11.9) implies that fs = N, Eq.(11.10)
implies that N > 6, and Eq.(11.11) implies that f = 1. Since we need N = 2m as well, we chose fs = N = 8.
f =
In Example 2, flow = 1 and fhigh = 2, and we again chose n = 3. Then, Eq.(11.6) implies that f = 1/3, Eq.(11.7)
implies that fs = N/3, and Eq.(11.8) implies that N > 12. Since we need N = 2m as well, we chose N = 16 and this
forces fs = 16/3.
23
The N real numbers F(0), F(t), F(2 t), ..., F(m t), ..., F((N 1) t) can be used to define N complex numbers
G(k f ), where k = 0, 1, ..., (N 1), according to (this incorporates Maximas conventions):
G(k f ) =
N1
1 X
F(m t) e2 i m k/N
N
(11.12)
m=0
N1
X
G(k f ) e2 i k m/N
(11.13)
k=0
(11.14)
N1
1 X
F(tm ) e2 i fk tm
N
(11.15)
m=0
and
F(tm ) =
N1
X
G(fk ) e2 i tm fk
(11.16)
k=0
where fk = k f and tm = m t.
A simpler looking set of transform pairs can be achieved by letting Fm = F(tm ) and Gk = G(fk ), in terms of which
Equations (11.12) and (11.13) become
N1
1 X
Fm e2 i m k/N
(11.17)
Gk =
N
m=0
and
Fm =
N1
X
Gk e2 i k m/N
(11.18)
k=0
We can use
e2 i m k = (e2 i k )m = (1)m = 1
(11.19)
(11.20)
We can now formally admit negative frequencies by letting k take on negative integral values, and setting k = N/2 we
then get
GN/2 = GN/2 .
(11.21)
24
This means that the amplitude corresponding to the Nyquist frequency
fNyquist =
N
f
2
(11.22)
is the same complex number as the amplitude corresponding to the frequency fNyquist .
In the qfft package, the function nyquist calculates what we call the Nyquist integer kNyquist , which is just
kNyquist =
N
,
2
(11.23)
in terms of which
fNyquist = kNyquist f
(11.24)
GN/2+1 = GN/2+1 .
(11.25)
N
1
=
,
fs
f
(11.26)
so that the fast Fourier amplitudes describe a signal which has the basic inevitable long period T no matter what other
shorter periods (and correspondingly higher frequencies) are also present in the signal. This low frequency, long period
property is an artifact of the approximate nature of Equations (11.12) and (11.13).
The fast fourier transform and its inverse should be considered as a distinct type of transform pair rather than as an
approximation to either a Fourier series expansion or a Fourier integral expression of a continuous spectrum. The basic
idea of the fast Fourier transform is that one has waited long enough for a physical system to settle down and the system
is then sampled for a certain finite length of time Ts (we use frequency-time language only for simplicity here, the same
ideas apply to wavelength-spatial domain problems).
25
1.
26
4.
5.
6.
7.
8.
9.
27
11.4 The Discrete Fourier Transform Derived via a Numerical Integral Approximation
Review of Trapezoidal Rule
If we let f0 = f (a), f1 = f (a + h), f2 = f (a + 2 h), ... and fN = f (b) = f (a + N h), then the trapezoidal rule approximation is
Z b
h
f (x) dx (f0 + 2 f1 + 2 f2 + + 2 fN1 + fN )
(11.27)
2
a
where b = a + N h defines h = (b a)/N. If we now specialize to functions such that f (a) = f (b) then the trapezoidal
rule reduces to
Z b
f (x) dx h (f (a) + f (a + h) + f (a + 2 h) + + f (b 2 h) + f (b h))
(11.28)
a
with h = (b a)/N.
If we now make the replacements x t, a 0, b T, h = (b a)/N T/N = t,
(b h) T (T/N) = (N 1) t, then
Z T
f (t) dt (T/N) (f (0) + f (t) + f (2 t) + + f ( (N 1) t) )
(11.29)
or
f (t) dt t
0
N1
X
f (m t)
(11.30)
m=0
Ck e2 i k t/T
(11.32)
k=
which would be a complex form of Fourier series expansion in terms of an infinite number of Fourier coefficients Ck . We
have adopted here sign and prefactor conventions which will lead us to Maximas fast Fourier conventions.
Now assume we only know the signal at N discrete values F(m t), where m = 0, 1, 2, ..., N 1, and that F(t) = f (t + T).
We can then approximate the integral in Eq.(11.31) using the trapezoidal approximation expressed by Eq.(11.30).
Ck
N1
X
1
(T/N)
F(m t) e2 i k m t/T
T
(11.33)
m=0
1
1
fs
=
=
T
t N
N
(11.34)
in which fs = 1/t is the sampling frequency, and making the replacements T 1/f , Ck G(k f )
N1
1 X
G(k f ) =
F(m t) e2 i (k f ) (m t)
N
m=0
(11.35)
28
With fk = k f and tm = m t, we can write this as
G(fk ) =
N1
1 X
F(tm ) e2 i fk tm
N
(11.36)
m=0
which we recognise as the same as Eq.(11.15). With only N values of F(tm ) we can only determine N values of G(fk ),
which by convention we take to be for the values of the integer k = 0, 1, 2, ..., N 1.
We see from Eq.(11.34) that
f t =
1
N
(11.37)
(11.38)
m=0
G(k f ) e2 i k n/N =
N1
N1
N1
X
1 X
1 X
F(m t)
e2 i k (nm)/N =
F(m t) (N m,n ) = F(n t)
N m=0
N m=0
(11.39)
k=0
which reproduces our discrete inverse Fourier transform formula Eq.(11.13), since n is an arbitrary integer.
That the sum over k is equal to zero if m 6= n can be seen by letting l = n m and using ek a = (ea )k and recognising that we
have a simple geometric sum. We can also let Maxima confirm this as follows:
(%i1) declare([k,l,N],integer)$
(%i2) sum (exp(2*%pi*%i*k*l/N),k,0,N-1),simpsum;
2 %i %pi l
%e
- 1
(%o2)
---------------2 %i %pi l
---------N
%e
- 1
(%i3) %,demoivre;
(%o3)
0
In the last step the exponentials of complex arguments are converted into their trig function equivalents using
ei = cos + i sin
(11.40)
Preface
COPYING AND DISTRIBUTION POLICY
This document is part of a series of notes titled
"Maxima by Example" and is made available
via the authors webpage http://www.csulb.edu/woollett/
to aid new users of the Maxima computer algebra system.
NON-PROFIT PRINTING AND DISTRIBUTION IS PERMITTED.
You may make copies of this document and distribute them
to others as long as you charge no more than the costs of printing.
These notes (with some modifications) will be published in book form
eventually via Lulu.com in an arrangement which will continue
to allow unlimited free download of the pdf files as well as the option
of ordering a low cost paperbound version of these notes.
Feedback from readers is the best way for this series of notes to become more helpful to new users of Maxima. All
comments and suggestions for improvements will be appreciated and carefully considered.
LOADING FILES
The defaults allow you to use the brief version load(fft) to load in the
Maxima file fft.lisp.
To load in your own file, such as qxxx.mac
using the brief version load(qxxx), you either need to place
qxxx.mac in one of the folders Maxima searches by default, or
else put a line like:
file_search_maxima : append(["c:/work2/###.{mac,mc}"],file_search_maxima )$
in your personal startup file maxima-init.mac (see later in this chapter
for more information about this).
Otherwise you need to provide a complete path in double quotes,
as in load("c:/work2/qxxx.mac"),
We always use the brief load version in our examples, which are generated
using the XMaxima graphics interface on a Windows XP computer, and copied
into a fancy verbatim environment in a latex file which uses the fancyvrb
and color packages.
The author would like to thank Maxima developer Barton Willis for his initial suggestion to use the Maxima
code file simplifying.lisp and his patient help in understanding how to make use of that code. The new
code has also been simplified (as compared with the rather long-winded code in version 1) by using a set of functions
shared by Barton Willis which are used in making decision branches. These functions are
mplusp, mtimesp, mnctimesp, mexptp, mncexptp.
(The nc additions refer to non-commutative). General expansions of multiple term arguments have been simplified
by using Barton Willis methods which combine lambda and xreduce.
12.1 References
The following works are useful sources. Some abbreviations (which will be used in the following sections) are defined
here.
Aitchison, I.J.R., Relativistic Quantum Mechanics, Barnes and Noble,1972
A/H: Aitchison,I.J.R, and Hey, A.J.G., Gauge Theories in Particle Physics, Adam Hilger, 1989
B/D: Bjorken, James D. and Drell, Sidney D, Relativistic Quantum Mechanics, McGraw Hill, 1964
BLP: Berestetskii, V. B, Lifshitz, E. M., and Pitaevskii, L. P., Quantum Electrodynamics, Course of Theoretical
Physics, Vol. 4, 2nd. Ed. Pergamon Press, 1982
Berestetskii, V. B, Lifshitz, E. M., and Pitaevskii, L. P., Relativistic Quantum Theory, Part 1, Course of Theoretical
Physics, Vol. 4, Pergamon Press, 1971
De Wit, B. and Smith, J., Field Theory in Particle Physics, North-Holland, 1986
G/R: Greiner, Walter, and Reinhardt, Joachim, Quantum Electrodynamics, fourth ed., Springer, 2009
Griffiths, Introduction to Elementary Particles, Harper and Row, 1987
H/M: Halzen, Francis and Martin, Alan D., Quarks and Leptons, John Wiley, 1984
I/Z: Itzykson, Claude and Zuber, Jean-Bernard, Quantum Field Theory, McGraw-Hill, 1980
Jauch, J.M., and Rohrlich, F., The Theory of Photons and Electrons, Second Expanded Edition, Springer-Verlag,
1976
Kaku, Michio, Quantum Field Theory, Oxford Univ. Press, 1993
Maggiore, Michele, A Modern Introduction to Quantum Field Theory, Oxford Univ. Press, 2005
P/S: Peskin, Michael E. and Schroeder, Daniel V., An Introduction to Quantum Field Theory, Addison-Wesley,
1995
Quigg, Chris, Gauge Theories of the Strong, Weak, and Electromagnetic Interactions, Benjamin/Cummings, 1983
Renton, Peter, Electroweak Interactions, Cambridge Univ. Press, 1990
Schwinger, Julian, Particles, Sources, and Fields, Vol. 1, Addison-Wesley, 1970
Sterman, George, An Introduction to Quantum Field Theory, Cambridge Univ. Press, 1993
Weinberg, Steven, The Quantum Theory of Fields, Vol.I, Cambridge Univ. Press, 1995
0 1
=
,
1 0
0
0 j
,
j 0
1 0
,
0 1
(12.1)
4
in which j for j = 1, 2, 3 are the 2 2 Pauli matrices
0 1
=
,
1 0
0 i
,
i 0
1 0
.
0 1
(12.2)
5 = i 0 1 2 3.
(12.3)
The lepton Dirac spinor is the four element column matrix u(p, ) where = +1 picks out positive helicity h = +1/2
and = 1 picks out negative helicity h = 1/2. The corresponding barred particle spinor is a four element row
matrix
u(p, ) = u 0
(12.4)
u(p, ) u(p, 0 ) = 2 m 0 ,
and we also have
, 0 = 1,
u(p, ) u(p, ) = /p + m,
(12.5)
(12.6)
in which a 4 4 unit matrix is understood to be multiplying the scalar mass symbol m, and /
p = p with use of the
summation convention.
The antilepton Dirac spinor is the four element column matrix v(p, ) in which = +1 picks out the positive helicity
h = +1/2 antiparticle state and = 1 picks out negative helicity h = 1/2 antiparticle state, is defined (with P/S
phase choice) via
v(p, ) = 5 u(p, )
(12.7)
v(p, ) = v 0
(12.8)
v(p, ) v(p, 0 ) = 2 m 0
We also have
, 0 = 1.
(12.9)
v(p, ) v(p, ) = /p m
(12.10)
1
(1 + 5 /sR (p))
2
(12.11)
S(p, ) =
in which the 1 is interpreted as the 4 4 unit matrix and in which /sR (p) = sR , and the right handed spin 4-vector
sr (p)
|p| E
,
p
m m
(12.12)
5
in which E =
m2 + p2 .
(12.13)
(12.14)
u(p, ) u(p, ) =
1
(1 + 5 ) /p
2
(12.15)
v(p, ) v(p, ) =
1
(1 5 ) /p.
2
(12.16)
Calculation of unpolarized cross sections requires summing the absolute value squared of a polarized amplitude over the
helicity quantum numbers of the particles involved, and the result can be written as the matrix trace of a 4 4 matrix. A
simple example follows. We use a compressed notation in which, for example, u1 stands for u(p1 , 1 ) and u2 stands for
u(p2 , 2 ). Let be an arbitrary 4 4 matrix.
One can show that
in which
Then
u2
(
u2 u1 ) = u1
(12.17)
= 0 0 .
(12.18)
|
u2 u1 | =
1 2
u2
u2 u1 u1
(12.19)
1 2
u2 ,
u2
.
=
(p/1 + m) .
(12.20)
Writing out the matrix indices explicitly, the sum becomes (using the summation convention for repeated matrix indices)
a b u2 b =
a b
u2 a
(12.21)
|
u2 u1 |2 = Trace {(p/2 + m) (p/1 + m) }.
(12.22)
1 2
= + 2 g I4
(12.23)
for Lorentz indices and which can have values (0, 1, 2, 3) and
5 = 5 .
(12.24)
6
Contraction Theorems
= 4 I4
(12.25)
= 2
(12.26)
= 4 g I4
(12.27)
A general contraction pattern for the case that the pair of contracting gamma matrices surround an odd number (3, 5, ...)
of gamma matrices: we get the order reversed times (2).
= 2
(12.28)
A general contraction pattern for the case that the pair of contracting gamma matrices surround an even number (4, 6, ...)
of gamma matrices: we get two terms with the first term bringing the last gamma to the front, and the second term being
the first term in reversed order, all multiplied by (2).
= 2 ( + )
(12.29)
Trace Theorems
The trace of the product of an odd number of gamma matrices is zero. For the trace of a product of an even number of
gamma matrices (including zero) is based on:
T r(I4 ) = 4
(12.30)
T r( ) = 4 g
(12.31)
T r( ) = 4 (g g g g + g g )
(12.32)
For the trace of a product of an even number of gamma matrices, we can use the general formula for the reduction of a
trace of a product of (N = even) matrices to a sum involving the traces of products of (N - 2) matrices.
Lets use a more efficient notation here:
(12.33)
The reduction formula is then (see, for example, Barger and Phillips, p. 550 or Kaku, p. 752):
tr(n1, n2, n3, n4, n5, n6) = g n1 n2 tr(n3, n4, n5, n6)
g n1 n3 tr(n2, n4, n5, n6) + g n1 n4 tr(n2, n3, n5, n6)
g n1 n5 tr(n2, n3, n4, n6) + g n1 n6 tr(n2, n3, n4, n5)
7
Gamma 5 Traces
Since 5 = i 0 1 2 3 is proportional to the product of an even number of gamma matrices, the trace of the product
of gamma5 by an odd number of gamma matrices is zero. Hence T r( 5 ) = 0 and T r( 5 ) = 0
When 5 is multiplied by an even number of gamma matrices, we have
T r( 5 ) = 0
(12.34)
T r( 5 ) = 0
(12.35)
T r( 5 ) = 4 i
(12.36)
For the cases that 5 is multiplied by six or eight gamma matrices, we have used the Chisholm-Kahane gamma matrix
identity which replaces a product of three Dirac gamma matrices by a series of four terms. With our (Peskin/Schroeder)
conventions, 0123 = +1 and 5 = +i 0 1 2 3 , that identity is (using the summation convention for the repeated
index ):
= g g + g i 5
(12.37)
Here is the symbolic calculation of the trace of the product of G5 with six gamma matrices.
(%i81) tr6:tr(G5,n1,n2,n3,n4,n5,n6);
(%o81) -4*%i*Eps(n1,n2,n3,n4)*Gm(n5,n6)+4*%i*Eps(n1,n2,n3,n5)*Gm(n4,n6)
-4*%i*Eps(n1,n2,n3,n6)*Gm(n4,n5)
-4*%i*Gm(n1,n2)*Eps(n3,n4,n5,n6)
+4*%i*Gm(n1,n3)*Eps(n2,n4,n5,n6)
-4*%i*Eps(n1,n4,n5,n6)*Gm(n2,n3)
Version 1 of the Dirac package produces a result we will call tr6comp (copied from a separate work session using
version 1):
(%i82) tr6comp : 4*%i*Eps(n3,n2,n1,n4)*Gm(n5,n6)-4*%i*Eps(n3,n2,n1,n5)*Gm(n4,n6)
+4*%i*Eps(n3,n2,n1,n6)*Gm(n4,n5)
-4*%i*Gm(n1,n2)*Eps(n3,n4,n5,n6)
+4*%i*Gm(n1,n3)*Eps(n2,n4,n5,n6)
-4*%i*Eps(n1,n4,n5,n6)*Gm(n2,n3)
If we take the difference, we do not get zero, because we are using a different algorithm in version 2, and the symbol Eps
is not declared antisymmetric by the package.
(%i83) tr6 - tr6comp;
(%o83) -4*%i*Eps(n3,n2,n1,n4)*Gm(n5,n6)-4*%i*Eps(n1,n2,n3,n4)*Gm(n5,n6)
+4*%i*Eps(n3,n2,n1,n5)*Gm(n4,n6)
+4*%i*Eps(n1,n2,n3,n5)*Gm(n4,n6)
-4*%i*Eps(n3,n2,n1,n6)*Gm(n4,n5)
-4*%i*Eps(n1,n2,n3,n6)*Gm(n4,n5)
However, use of noncov introduces eps4, which is declared antisymmetic, and shows the results are equivalent when
the antisymmetry is taken into account.
(%i84) noncov(%);
(%o84) 0
8
Here we calculate a trace of gamma5 multiplied by eight gamma matrices:
(%i85) tr8:tr(G5,n1,n2,n3,n4,n5,n6,n7,n8);
(%o85) -4*%i*Eps(n1,n2,n3,n4)*Gm(n5,n6)*Gm(n7,n8)
+4*%i*Eps(n1,n2,n3,n5)*Gm(n4,n6)*Gm(n7,n8)
-4*%i*Eps(n1,n2,n3,n6)*Gm(n4,n5)*Gm(n7,n8)
-4*%i*Gm(n1,n2)*Eps(n3,n4,n5,n6)*Gm(n7,n8)
+4*%i*Gm(n1,n3)*Eps(n2,n4,n5,n6)*Gm(n7,n8)
-4*%i*Eps(n1,n4,n5,n6)*Gm(n2,n3)*Gm(n7,n8)
+4*%i*Eps(n1,n2,n3,n4)*Gm(n5,n7)*Gm(n6,n8)
-4*%i*Eps(n1,n2,n3,n5)*Gm(n4,n7)*Gm(n6,n8)
+4*%i*Eps(n1,n2,n3,n7)*Gm(n4,n5)*Gm(n6,n8)
+4*%i*Gm(n1,n2)*Eps(n3,n4,n5,n7)*Gm(n6,n8)
-4*%i*Gm(n1,n3)*Eps(n2,n4,n5,n7)*Gm(n6,n8)
+4*%i*Eps(n1,n4,n5,n7)*Gm(n2,n3)*Gm(n6,n8)
-4*%i*Eps(n1,n2,n3,n4)*Gm(n5,n8)*Gm(n6,n7)
+4*%i*Eps(n1,n2,n3,n5)*Gm(n4,n8)*Gm(n6,n7)
-4*%i*Eps(n1,n2,n3,n8)*Gm(n4,n5)*Gm(n6,n7)
-4*%i*Gm(n1,n2)*Eps(n3,n4,n5,n8)*Gm(n6,n7)
+4*%i*Gm(n1,n3)*Eps(n2,n4,n5,n8)*Gm(n6,n7)
-4*%i*Eps(n1,n4,n5,n8)*Gm(n2,n3)*Gm(n6,n7)
+4*%i*Eps(n1,n2,n3,n6)*Gm(n4,n7)*Gm(n5,n8)
-4*%i*Eps(n1,n2,n3,n7)*Gm(n4,n6)*Gm(n5,n8)
-4*%i*Eps(n1,n2,n3,n6)*Gm(n4,n8)*Gm(n5,n7)
+4*%i*Eps(n1,n2,n3,n8)*Gm(n4,n6)*Gm(n5,n7)
-4*%i*Gm(n1,n2)*Gm(n3,n4)*Eps(n5,n6,n7,n8)
+4*%i*Gm(n1,n3)*Gm(n2,n4)*Eps(n5,n6,n7,n8)
-4*%i*Gm(n1,n4)*Gm(n2,n3)*Eps(n5,n6,n7,n8)
+4*%i*Eps(n1,n2,n3,n7)*Gm(n4,n8)*Gm(n5,n6)
-4*%i*Eps(n1,n2,n3,n8)*Gm(n4,n7)*Gm(n5,n6)
+4*%i*Gm(n1,n2)*Gm(n3,n5)*Eps(n4,n6,n7,n8)
-4*%i*Gm(n1,n3)*Gm(n2,n5)*Eps(n4,n6,n7,n8)
+4*%i*Gm(n1,n5)*Gm(n2,n3)*Eps(n4,n6,n7,n8)
-4*%i*Gm(n1,n2)*Eps(n3,n6,n7,n8)*Gm(n4,n5)
+4*%i*Gm(n1,n3)*Eps(n2,n6,n7,n8)*Gm(n4,n5)
-4*%i*Eps(n1,n6,n7,n8)*Gm(n2,n3)*Gm(n4,n5)
(%i86) length(%);
(%o86) 33
The present package function simp_tr1 (which controls tr1 via the lisp code in simplifying-new.lisp) does
not return an evaluation for the case of an even number equal to ten or more gamma matrices multiplying G5.
(%i2) tr10:tr(G5,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10);
"simp_tr1: present version of tr only returns nonzero gamma5 traces for"
" G5 times a product of 4,6,or 8 gammas"
(%o2) Gamma5trace(G5,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10)
(%i93) Mindex(n11,n12);
(%o93) done
(%i94) indexL;
(%o94) [n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,la,mu,nu,rh,si,ta,al,be,ga,de,ep,n11,
n12]
(%i95) tr11:tr(G5,n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,n11);
(%o95) 0
More compact expressions for gamma 5 traces (compared to the classical methods used here) can be found in the paper:
A new method for calculation of traces of Dirac gamma-matrices
in Minkowski space, by Alexander L. Bondarev,
http://arxiv.org/abs/hep-ph/0504223
ver: ",_binfo%,"
date: ",mydate )$
which prints out the Maxima version number and year-month-day as:
ver:
Maxima 5.23.2
date:
2011-02-28
10
11
4-momentum array p[mu].
A symbolic product which includes the gamma5 matrix 5 , represented symbolically by G5, is G(G5,mu,p1,nu,p2),
for example, and corresponds to: Gam[5] . Gam[mu] . sL(p1) . Gam[nu] . sL(p2). The arrays Gam[mu]
and Gam[5] are 4 x 4 matrices, as is the matrix function sL(p), and they are defined in dgmatrix2.mac, where
you can also find the definitions of the Dirac particle spinor (4-component column vector) UU, and the Dirac anti-particle
spinor (also a 4-component column vector) VV, (both defined using Maximas matrix function) and having a concrete
form which is generated from the specified 4-momentum and helicity of the particle or anti-particle. Many examples of
explicit matrix methods (based on dgmatrix2.mac code) will be found in the twelve batch file problems worked out.
The file dirac2.mac includes some definitions of useful utility functions, and also defines the explicit numerical metric
tensor array gmet[mu,nu] and the explicit four dimensional completely antisymmetric tensor array
eps4[mu,nu,rh,si] components (and antisymmetry property). (The Lorentz indices mu, nu,... take values 0,1,2,3.)
dirac2.mac also declares that the symbolic four vector dot product D(p,q) is symmetric, as is the symbolic metric
tensor Gm(mu,nu), as an aid in automatic simplification of expressions.
The function noncov converts Eps(mu,nu,rh,si) to eps4[mu,nu,rh,si] (with the convention that 0 1 2 3 = 1),
converts Gm(mu,nu) to gmet[mu,nu], converts UI(p,mu) to p[mu], converts LI(p,mu) to
sum (gmet[mu,nu]*p[nu],nu,0,3). For example LI (p,0) --> p[0], LI (p,1) --> -p[1]. The
function noncov also converts D(p,q) into sum (sum (gmet[mu,nu]*p[mu]*q[nu],nu,0,3),mu,0,3),
which reduces to the single sum sum (gmet[mu,mu]*p[mu]*q[mu],mu,0,3), which becomes the explicit sum
p[0]*q[0] - p[1]*q[1] - p[2]*q[2] - p[3]*q[3]. The function noncov does nothing to G(...).
The reference frame dependent function comp_def (p(Ep,px,py,pz)) creates an array with the name p whose
elements can be viewed using listarray (p) and whose elements can be accessed by using p[0] to get the value
Ep, using p[1] to get the value px, etc.
The symbolic trace of a product of gamma matrices is usually carried out using the tr function. Thus the syntax
tr(mu,nu,rh,si) carries out the trace of a product of four Dirac gamma matrices, and the same calculation can
be carried out using explicit Maxima matrices using the syntax:
mat_trace (Gam[mu] . Gam[nu] . Gam[rh] . Gam[si]);
(although one must supply definite values for the Lorentz index symbols mu, nu, rh, si to get a simple result
from the explicit matrix method ).
A simpler-to-use function for the trace of explicit matrix expressions is m_tr. For example, m_tr (mu,p,q,nu) uses
the exact same syntax as tr but internally translates this into
mat_trace (Gam[mu] . sL(p) . sL(q) . Gam[nu]).
To obtain useful expressions from the explicit matrix methods, one should first use comp_def to define the frame dependent components of relevant 4-momenta, then use either the m_tr or mat_trace syntax for the trace, and then use
Con (or mcon) for contraction.
A symbolic trace involving a gamma5 matrix, such as tr (G5,p,nu,rh,si) generates expressions proportional
to (for example) LI(p,N1)*Eps (N1,nu,rh,si), in which N1 is an unsummed dummy index created by the
code. (The sum over that dummy index is done by the later use of noncov.) The global symbol Nlast will always tell you what the last dummy symbol created is. The symbolic tr code creates these dummy indices in the order
N1,N2,... and establishes indexp and dummyp attributes, so that, for example, indexp (N1) --> true and
dummyp (N1) --> true.
An expression or sum of terms involving G(a,b,c,..)s can be converted into an expression (or sum of such) in
which each G(...) is replace by tr (...) by using the symbolic function Gtr.
Thus Gtr (G(a,b,c,d)) --> tr (a,b,c,d).
12
The symbolic trace function tr automatically contracts on repeated Lorentz indices, such as in tr (mu,p,q,mu),
before using the actual trace algorithms.
Symbolic contraction (without the trace) on repeated indices in a symbolic product of gamma matrices can be done using
Con, which recognises a symbolic case and then calls scon. Examples in which scon (s for symbolic) is called by
Con are: Con (G (mu,p,q,mu)) (equivalent to scon(G(mu,p,q,mu)))
and
Con (G (mu,G5,mu)) (equivalent to scon(G(mu,G5,mu))).
Con (and scon) automatically contract on all repeated Lorentz indices unless the user supplies the desired contraction
indices.
For example, Con (G(mu,nu,p,q,nu,mu),mu,nu) (or the same with Con --> scon) will carry out symbolic
contraction on both mu and nu and produce the same answer as Con (G(mu,nu,p,q,nu,mu)).
But Con (G(mu,nu,p,q,nu,mu),nu) will only contract on nu.
When using explicit Dirac gamma matrices and Maxima matrix methods, you must always supply the desired contraction indices to Con (which will recognise the explicit matrix case and call mcon with the desired contraction indices).
For example,
Con (mat_trace (Gam[mu] . sL(p) . sL(q) . Gam[mu]), mu) or the same with Con --> mcon .
A frequent case met with in the twelve examples is the symbolic contraction of a product of symbolic traces each produced
by tr. The most efficient symbolic method is to first convert each of the symbolic trace expressions into expressions depending on eps4, gmet, and 4-momentum components like p[1] by using noncov before the contraction. This is
such a common approach, that the package function nc_tr is defined to immediately apply noncov to each trace result
returned from the function tr1 (controlled by simp_tr1 via simplifying-new.lisp) called by TR1, which is
called by tr.
One then needs the contraction of products of such expressions, which is provided by using either the contraction
function econ (e for explicit) or (usually quicker in operation) mcon. You could simply use Con (which should
recognise the post-noncov case and call econ with the supplied contraction indices). As in the explicit matrix case, you
must supply the desired contraction indices (in this third case) to accomplish the desired contraction.
In the following introductory examples, carried out in an interactive context, you will see examples of all of the above for
both traces and contractions.
13
12.4.1 Some Basic Package Symbols
In the initial examples, no values have been assigned to the 4-momenta array components referred to (this will eventually be done using the package function comp_def), so we will see things like p[1] for example. The last line of
dirac2.mac is display2d:false$, which allows more information per screen, especially when displaying matrices.
(%i1) load(dirac2);
dirac2.mac
simplifying-new.lisp
dgtrace2.mac
dgcon2.mac
dgeval2.mac
dgmatrix2.mac
scalarL = [c1, c2, c3, c4, c5, c6, c7, c8, c9, c10]
indexL = [n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, la, mu, nu, rh, si, ta, al,
be, ga, de, ep]
massL = [m, M]
Nlast = 0
reserved program capital letter name use:
Chi, Con, D, Eps, G, G(1), G5, G5p, Gam, Gm, Gtr, LI, Nlast, UI, P, S, Sig
UU, VP, VV, I2, Z2, CZ2, I4, Z4, CZ4, RZ4, N1,N2,...
reserved array names: gmet, eps4
(%o1) "c:/work5/dirac2.mac"
(%i2) noncov(Eps(mu,nu,rh,si));
(%o2) eps4[mu,nu,rh,si]
(%i3) noncov (Eps(mu,nu,al,be));
(%o3) eps4[al,be,mu,nu]
(%i4) Eps(0,1,2,3);
(%o4) Eps(0,1,2,3)
(%i5) eps4 [0,1,2,3];
(%o5) 1
(%i6) eps4 [1,0,2,3];
(%o6) -1
(%i7) noncov (Gm (mu,nu));
(%o7) gmet[mu,nu]
(%i8) Gm (0,0);
(%o8) Gm(0,0)
(%i9) gmet[0,0];
(%o9) 1
(%i10) gmet[1,1];
(%o10) -1
(%i11) Gm (be,al);
(%o11) Gm(al,be)
(%i12) noncov (D(p,q));
(%o12) -p[3]*q[3]-p[2]*q[2]-p[1]*q[1]+p[0]*q[0]
(%i13) D (q,p);
(%o13) D(p,q)
(%i14) D(b,a);
(%o14) D(a,b)
(%i15) noncov (UI(p,0));
(%o15) p[0]
(%i16) noncov (UI(p,1));
(%o16) p[1]
(%i17) noncov (LI (p,0));
(%o17) p[0]
(%i18) noncov (LI (p,1));
(%o18) -p[1]
(%i19) massL;
(%o19) [m,M]
(%i20) Mmass (m1,m2);
(%o20) done
14
(%i21)
(%o21)
(%i22)
(%o22)
(%i23)
(%o23)
(%i24)
(%o24)
(%i25)
(%o25)
(%i26)
(%o26)
(%i27)
(%o27)
massL;
[m,M,m1,m2]
map (massp,%);
[true,true,true,true]
indexL;
[n1,n2,n3,n4,n5,n6,n7,n8,n9,n10,la,mu,nu,rh,si,ta,al,be,ga,de,ep]
map (indexp,%);
[true,true,true,true,true,true,true,true,true,true,true,true,true,true,
true,true,true,true,true,true,true]
scalarL;
[c1,c2,c3,c4,c5,c6,c7,c8,c9,c10]
map (scalarp,%);
[true,true,true,true,true,true,true,true,true,true]
noncov (G (mu,p1,nu,p2) );
G(mu,p1,nu,p2)
With this (default) list of recognised Lorentz indices, the expression G(mu,a,nu,b) would represent the matrix product
Gam[mu] . sL(a) . Gam[nu] . sL(b).
The package function Gexpand will expand symbolic products of Dirac gamma matrices, expanding arguments with
multiple terms, pulling out numbers and declared scalars, and making mass expansions when finding a term which is a
15
recognised mass symbol.
An additional expansion occurs (using Gexpand) if a slot contains the symbol S(sv) or S(sv,Sp) which are used to
symbolically represent heliciy projection matrices (the simpler first case for particles treated as massless, and the more
complicated two argument version for the more general case of massive particles).
The symbol sv is a standin of the helicity quantum number taken to have values sv = 1 or sv = -1. The symbol Sp
represents the positive helicity spin 4-vector implied by a particles 4-momentum vector. Many examples of the use of
helicity projection operator methods will be shown in the reaction examples. When Gexpand encounters such a helicity
projection operator symbol an expansion is made using the symbolic gamma5 matrix G5.
(%i12)
(%o12)
(%i13)
(%o13)
Gexpand (G (S(sv)));
sv*G(G5)/2+G(1)/2
Gexpand (G (S(sv,Sp)));
sv*G(G5,Sp)/2+G(1)/2
Note especially that the symbol G(1) represents symbolically the unit 4 x 4 matrix, whose trace is 4.
The package trace functions tr, Gtr, and nc_tr all use the function Gexpand as the first step in calculating a trace of
a product of Dirac gamma matrices symbolically.
Here are some examples of the use of Gexpand.
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
(%i17)
(%o17)
(%i18)
(%o18)
(%i19)
(%o19)
(%i20)
(%o20)
(%i21)
(%o21)
(%i22)
(%o22)
(%i23)
(%o23)
(%i24)
(%o24)
(%i25)
(%o25)
(%i26)
(%o26)
(%i27)
(%o27)
Gexpand (G());
G()
Gexpand (G(1));
G(1)
Gexpand (G(-1));
-G(1)
Gexpand (G(-a));
-G(a)
Gexpand (G(m));
G(1)*m
Gexpand (G(a + m));
G(1)*m+G(a)
Gtr (%);
4 *m
Gexpand (G(a,b+c));
G(a,c)+G(a,b)
Gtr (%);
4*D(a,c)+4*D(a,b)
Gexpand (G (a+m,b+M));
G(1)*m*M+G(a)*M+G(b)*m+G(a,b)
Gtr (%);
4*m*M+4*D(a,b)
Gexpand (G (S(1),a,S(1),b));
G(G5,a,G5,b)/4+G(G5,a,b)/4+G(a,G5,b)/4+G(a,b)/4
Gexpand (G (2*c1*a,3*c2*b - c3*c/7));
6*c1*c2*G(a,b)-2*c1*c3*G(a,c)/7
Gtr(%);
24*c1*c2*D(a,b)-8*c1*c3*D(a,c)/7
16
12.4.4 Symbolic and Explicit Matrix Trace Examples: tr, Gtr, mat trace, m tr
Some Symbolic Trace Examples
We next display some examples of symbolic traces.
The symbol G5 symbolically represents 5 .
The symbol Gm(mu,nu) whose arguments are both recognised Lorentz index symbols, represents symbolically either
g or g , depending on the context.
The symbol UI(p,mu) (upper index) symbolically represents p .
The symbol LI(p,mu) (lower index) symbolically represents p .
The symbol Eps (la,mu,nu,rh) represents symbolically .
(%i2) tr(1);
(%o2) 4
(%i3) Gtr (G(1));
(%o3) 4
(%i4) tr(mu);
(%o4) 0
(%i5) tr(mu,nu);
(%o5) 4*Gm(mu,nu)
(%i6) Gtr (G (mu,nu));
(%o6) 4*Gm(mu,nu)
(%i7) tr(p,q);
(%o7) 4*D(p,q)
(%i8) tr(p,mu);
(%o8) 4*UI(p,mu)
(%i9) noncov(%);
(%o9) 4*p[mu]
(%i10) tr(mu,p);
(%o10) 4*UI(p,mu)
(%i11) tr(G5);
(%o11) 0
(%i12) tr(G5,mu);
(%o12) 0
(%i13) tr (G5,mu,nu);
(%o13) 0
(%i14) tr (G5,mu,nu,rh);
(%o14) 0
(%i15) tr (G5,al,be,la,mu);
(%o15) -4*%i*Eps(al,be,la,mu)
(%i16) noncov(%);
(%o16) -4*%i*eps4[al,be,la,mu]
(%i17) tr(la,mu,nu,rh);
(%o17) 4*Gm(la,mu)*Gm(nu,rh)-4*Gm(la,nu)*Gm(mu,rh)+4*Gm(la,rh)*Gm(mu,nu)
(%i18) tr (a,b,c,d);
(%o18) 4*D(a,b)*D(c,d)-4*D(a,c)*D(b,d)+4*D(a,d)*D(b,c)
(%i19) tr(G5,p,be,la,mu);
(%o19) -4*%i*LI(p,N1)*Eps(N1,be,la,mu)
(%i136) tr(G5,mu,nu,rh,al);
(%o136) -4*%i*Eps(mu,nu,rh,al)
(%i137) tr(mu,G5,nu,rh,al);
(%o137) 4*%i*Eps(mu,nu,rh,al)
(%i138) tr(mu,nu,G5,rh,al);
(%o138) -4*%i*Eps(mu,nu,rh,al)
(%i139) tr(mu,nu,rh,G5,al);
(%o139) 4*%i*Eps(mu,nu,rh,al)
(%i140) tr(mu,nu,rh,al,G5);
(%o140) -4*%i*Eps(mu,nu,rh,al)
17
Some Simple Explicit Matrix Trace Examples
Next are some very simple examples of the use of explicit matrix trace methods. I4 is an explicit unit matrix in 4
dimensions, and Z4 is an explicit zero matrix in 4 dimensions.
(%i21)
(%o21)
(%i22)
(%o22)
(%i23)
(%o23)
(%i24)
(%o24)
(%i25)
(%i26)
(%i27)
(%i28)
(%o28)
(%i30)
I4;
matrix([1,0,0,0],[0,1,0,0],[0,0,1,0],[0,0,0,1])
mat_trace(%);
4
Z4;
matrix([0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0])
mat_trace (%);
0
a(mu,nu):=mat_trace(Gam[mu] . Gam[nu])$
b(mu,nu):=4*gmet[mu,nu]$
c(mu,nu):=is(equal(a(mu,nu),b(mu,nu)))$
c(0,0);
true
for mu : 0 thru 3 do
for nu : 0 thru 3 do
if not c(mu,nu) then print(mu,nu," false")$
In the last step, we have shown that a(mu,nu) = b(mu,nu) for all 16 mu,nu pairs, since there were no false
messages printed to the screen.
More Symbolic Trace Examples
Returning to the symbolic trace with tr, recognised mass symbols get special treatment.
(%i31)
(%o31)
(%i32)
(%o32)
(%i33)
(%o33)
tr(m+p1,mu,m+p2,mu);
16*m2-8*D(p1,p2)
tr(m,m);
4*m2
tr(m,M);
4 *m*M
The arguments of tr(m+p1,mu,m+p2,mu) are examined to look for mass terms, and if any are found those arguments are expanded and the mass symbols are factored out of the tr function. An argument like p + m in tr is treated
like the matrix sum sL(p) + m*I4 and a parallel treatment using explicit matrix methods needs to have the mass symbol multiplied by I4.
The last two simple examples can be reproduced using mat_trace, but we have to be careful to use parentheses around
the quantity m*I4, since the Maxima function mat_trace does not know anything about special mass symbols.
(%i35) mat_trace((m*I4) . (m*I4));
(%o35) 4*m2
Likewise, numbers and recognised scalars which multiply and/or divide momentum symbols are factored out of tr
arguments.
(%i36)
(%o36)
(%i37)
(%o37)
(%i38)
(%o38)
(%i39)
(%o39)
(%i40)
(%o40)
scalarL;
[c1,c2,c3,c4,c5,c6,c7,c8,c9,c10]
tr(c1*p,q);
4*c1*D(p,q)
tr(-c1*p,q/c2);
-4*c1*D(p,q)/c2
tr(-c1*%i*p,q/c2);
-4*%i*c1*D(p,q)/c2
tr(-7*c1*%i*p,q/c2/10);
-14*%i*c1*D(p,q)/(5*c2)
18
Factoring out scalars, etc., occurs after multiple term arguments are first expanded.
(%i41)
(%o41)
(%i42)
(%o42)
(%i43)
(%o43)
tr(a,b);
4*D(a,b)
tr(a,b+c);
4*D(a,c)+4*D(a,b)
tr(a,c1*b+c2*c+c3*d);
4*c3*D(a,d)+4*c2*D(a,c)+4*c1*D(a,b)
The last example shows a contraction between an index which appears in a Gm and a multiplying Eps. scon calls
get_rind to find repeated indices and then simp_scon1 to automatically contract on repeated indices, which it will
19
do for a product of Gm(..) and Eps(..). looks for repeated indices.
If we try the same contraction with Con we get
(%i13) Con (Gm (n1,n2)*Eps (n1,n3,n4,n5));
(%o13) gmet[n1,n2]*eps4[n1,n3,n4,n5]
which occurs because Con calls Eps_facp, (which returns true), thus detecting the presence of an Eps factor in the
expression, and as a consequence, calls noncov immediately, followed by a call to econ. noncov converts Gm( ) to
gmet[ ] and Eps( ) to eps4[ ]. econ will not automatically contract; you must supply the contraction index.
(%i14) Con (Gm (n1,n2)*Eps (n1,n3,n4,n5),n1);
(%o14) eps4[n2,n3,n4,n5]
Note that the present version of scon will not simplify a product of two Eps factors.
(%i17)
(%o17)
(%i18)
(%o18)
scon(Eps(n1,n2,n3,n4)*Eps(n1,n5,n6,n7));
Eps(n1,n2,n3,n4)*Eps(n1,n5,n6,n7)
scon(Eps(n1,n2,n3,n4)*Eps(n1,n5,n6,n7),n1);
Eps(n1,n2,n3,n4)*Eps(n1,n5,n6,n7)
However, you can use Con (supplying the contraction index as well) which again will detect the Eps factors, then will
call noncov and econ to do the summatation over the contraction index.
(%i16) Con(Eps(n1,n2,n3,n4)*Eps(n1,n5,n6,n7),n1);
(%o16) -eps4[3,n2,n3,n4]*eps4[3,n5,n6,n7]-eps4[2,n2,n3,n4]*eps4[2,n5,n6,n7]
-eps4[1,n2,n3,n4]*eps4[1,n5,n6,n7]
+eps4[0,n2,n3,n4]*eps4[0,n5,n6,n7]
noncov (Eps(n1,n2,n3,n4)*Eps(n1,n5,n6,n7));
eps4[n1,n2,n3,n4]*eps4[n1,n5,n6,n7]
econ (%,n1);
-eps4[3,n2,n3,n4]*eps4[3,n5,n6,n7]-eps4[2,n2,n3,n4]*eps4[2,n5,n6,n7]
-eps4[1,n2,n3,n4]*eps4[1,n5,n6,n7]
+eps4[0,n2,n3,n4]*eps4[0,n5,n6,n7]
The present version of the Dirac package does not simplify the implied contraction presented by
Con (Eps (n1,n2,n3,n4)*Eps (n1,n5,n6,n7),n1). Using the corresponding expression with Eps(...)
replaced by eps4[...] and then using econ (or Con) will return a contracted expression in terms of eps4s.
(%i34)
(%o34)
(%i37)
(%o37)
(%i35)
(%o35)
(%i36)
(%o36)
20
Examples of Explicit Matrix Contractions on Repeated Lorentz Indices Using Con
(%i26)
(%o26)
(%i27)
(%o27)
(%i28)
(%o28)
(%i29)
(%o29)
(%i30)
(%o30)
(%i32)
(%o32)
(%i23)
(%o23)
(%i24)
(%o24)
The use of noncov will automatically sum over all dummy indices.
(%i12) noncov(Eps(N1,N2,N3,N4)*Eps(N1,N2,N3,N4));
(%o12) 24
21
However, the above result is NOT what is meant by contraction. True contraction of indices includes both lowering one
of each pair of indices and then summing, and this operation is correctly carried out by econ.
(%i13) econ(eps4[n1,n2,n3,n4]*eps4[n1,n2,n3,n4],n1,n2,n3,n4);
(%o13) -24
Here are a few more comparisons between noncov and econ in this eps4 product context:
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
(%i17)
(%o17)
(%i18)
(%o18)
(%i19)
(%o19)
noncov(Eps(N1,N2,N3,0)*Eps(N1,N2,N3,0));
6
econ(eps4[n1,n2,n3,0]*eps4[n1,n2,n3,0],n1,n2,n3);
-6
noncov(Eps(N1,N2,N3,0)*Eps(N1,N2,N3,1));
0
econ(eps4[n1,n2,n3,0]*eps4[n1,n2,n3,1],n1,n2,n3);
0
noncov(Eps(N1,N2,0,1)*Eps(N1,N2,0,1));
2
econ(eps4[n1,n2,0,1]*eps4[n1,n2,0,1],n1,n2);
2
22
12.4.7 Contraction of a Product of Traces: Con, scon, mcon, econ
In the example of the high energy scattering of electrons in the center of momentum frame, worked out in the batch file
moller1.mac later, we need the contraction of the product of two traces, followed by a reduction to the kinematic
variables.
We will obtain a correct answer three different ways here.
METHOD1: We first find the symbolic traces, and then the symbolic contractions, followed by use of noncov. We call
this method1.
(%i1) load(dirac2);
[launch data edited out here]
(%o1) "c:/work5/dirac2.mac"
(%i2) assume(E > 0,th >= 0,th <= %pi)$
(%i3) comp_def(p1(E,0,0,E),p2(E,0,0,-E),p3(E,E*sin(th),0,E*cos(th)),
p4(E,-E*sin(th),0,-E*cos(th)))$
(%i4) tr1 : tr(p3,mu,p1,nu);
(%o4) 4*UI(p1,mu)*UI(p3,nu)+4*UI(p1,nu)*UI(p3,mu)-4*Gm(mu,nu)*D(p1,p3)
(%i5) tr2 : tr(p4,mu,p2,nu);
(%o5) 4*UI(p2,mu)*UI(p4,nu)+4*UI(p2,nu)*UI(p4,mu)-4*Gm(mu,nu)*D(p2,p4)
(%i6) method1a : scon (tr1*tr2);
(%o6) 32*D(p1,p2)*D(p3,p4)+32*D(p1,p4)*D(p2,p3)
(%i7) method1b : Con (tr1*tr2);
(%o7) 32*D(p1,p2)*D(p3,p4)+32*D(p1,p4)*D(p2,p3)
(%i8) method1c : Con (tr1*tr2,mu,nu);
(%o8) 32*D(p1,p2)*D(p3,p4)+32*D(p1,p4)*D(p2,p3)
(%i9) method1 : noncov (method1a);
(%o9) 32*cos(th)2*E4+64*cos(th)*E4+160*E4
METHOD2: We use nc_tr. This is a special function which is not just tr followed by noncov, but rather as TR1
generates the trace of each term of the initial argument expansion, the function noncov is immediately applied to the
trace result, and the output is accumulated in a sum which is eventually returned by nc_tr.
The contraction of uncontracted repeated Lorentz indices can then be effected using mcon, or econ (which Con should
call automatically by recognising the typical after-effects of noncov).
We will call this method2. We will see that method2 produces an apparently different trigonometric result, but use of
trigsimp, followed by expand, results finally in the same answer as found for method1.
(%i10) nctr1 : nc_tr(p3,mu,p1,nu);
(%o10) 4*gmet[mu,nu]*cos(th)*E2-4*gmet[mu,nu]*E2+4*p1[mu]*p3[nu]
+4*p3[mu]*p1[nu]
(%i11) nctr2 : nc_tr(p4,mu,p2,nu);
(%o11) 4*gmet[mu,nu]*cos(th)*E2-4*gmet[mu,nu]*E2+4*p2[mu]*p4[nu]
+4*p4[mu]*p2[nu]
(%i12) method2a : mcon (nctr1*nctr2,mu,nu);
(%o12) 64*sin(th)2*E4+96*cos(th)2*E4+64*cos(th)*E4+96*E4
(%i13) method2b : econ (nctr1*nctr2,mu,nu);
(%o13) 64*sin(th)2*E4+96*cos(th)2*E4+64*cos(th)*E4+96*E4
(%i14) method2c : Con (nctr1*nctr2,mu,nu);
(%o14) 64*sin(th)2*E4+96*cos(th)2*E4+64*cos(th)*E4+96*E4
(%i15) method2 : expand (trigsimp (method2a));
(%o15) 32*cos(th)2*E4+64*cos(th)*E4+160*E4
(%i16) method2 - method1;
(%o16) 0
We now obtain the same answer using the explicit matrix route, calling this method3. In this case, Con will call mcon
for the contraction, and again, we must supply the desired contraction indices. Using the more compact (but still explicit
matrix) syntax of m_tr, we call the result method3a:
23
(%i17)
(%o17)
(%i18)
(%o18)
(%i19)
(%o19)
method3a : Con(m_tr(p3,mu,p1,nu)*m_tr(p4,mu,p2,nu),mu,nu);
64*sin(th)2*E4+96*cos(th)2*E4+64*cos(th)*E4+96*E4
method3a : expand (trigsimp (%));
32*cos(th)2*E4+64*cos(th)*E4+160*E4
method3a - method1;
0
Now, using the transparently explicit matrix route with mat_trace, we call the result method3b.
(%i20) method3b : Con(mat_trace(sL(p3) . Gam[mu] . sL(p1) . Gam[nu])
*mat_trace(sL(p4) . Gam[mu] . sL(p2) . Gam[nu]),mu,nu);
(%o20) 64*sin(th)2*E4+96*cos(th)2*E4+64*cos(th)*E4+96*E4
(%i21) method3b : expand (trigsimp (%));
(%o21) 32*cos(th)2*E4+64*cos(th)*E4+160*E4
(%i22) method3b - method1;
(%o22) 0
As a passing remark, it is easy to verify two properties of Gam[5] using explicit matrices. First, Gam[5] has zero trace,
and then that the matrix product of Gam[5] with itself results in the unit 4 x 4 matrix:
(%i23)
(%o23)
(%i24)
(%o24)
mat_trace(Gam[5]);
0
is (equal (Gam[5] . Gam[5],I4));
true
24
25
(%i36)
(%o36)
(%i37)
(%o37)
(%i38)
(%o38)
M1n_s - M1n_m;
0
M1n_sm - M1n_m;
0
M1n_sc - M1n_m;
0
26
12.4.10 Polarized Amplitudes for (electron,positron) (muon, antimuon)
High Energy Limit Dirac Spinor Polarized Amplitudes
In the following example, we construct spinors needed to calculate the matrix element for the RL --> RL process
of the process (electron, positron ) --> (muon, antimuon),
e(-,p1,1) + e(+,p2,-1) --> mu(-,p3,1) + mu(+,p4,-1), in the high energy limit in which we neglect
the mass of the particles compared with their relativistic energy. (See Peskin/Schroeder, p.131 ff for details.)
The incident electron has attributes p1,sv1 = 1 and is represented by the spinor up1 (a column vector), the incident
positron has attributes p2, sv2 = -1 and is represented by the barred antiparticle spinor vp2b (a row vector). The
outgoing muon has attributes p3 and sv3 = 1 and is represented by the barred particle spinor up3b (a row vector), the
outgoing antimuon has attributes p4 and sv4 = -1 and is represented by the antiparticle spinor vp4 (a column vector).
Since in the high energy limit the energy and 3-momentum magnitude are the same (ignoring mass), we replace p by E,
and we are working in the center of momentum frame, so each particle has the same energy.
(%i1) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) comp_def (p1(E,0,0,E),
p2(E,0,0,-E),
p3(E,E*sin(th),0,E*cos(th)),
p4(E,-E*sin(th),0,-E*cos(th)))$
(%i3) listarray(p3);
(%o3) [E,sin(th)*E,0,cos(th)*E]
(%i4) up1 : UU(E,E,0,0,1);
(%o4) matrix([0],[0],[sqrt(2*E)],[0])
(%i5) vp2b : sbar (VV (E,E,%pi,0,-1));
(%o5) matrix([0,-sqrt(2*E),0,0])
(%i6) a12 : vp2b.Gam[mu].up1;
(%o6) matrix([0,-sqrt(2*E),0,0]) . Gam[mu] . matrix([0],[0],[sqrt(2*E)],[0])
(%i7) up3b : sbar (UU (E,E,th,0,1));
(%o7) matrix([cos(th/2)*sqrt(2*E),sin(th/2)*sqrt(2*E),0,0])
(%i8) vp4 : VV (E,E,%pi-th,%pi,-1);
(%o8) matrix([0],[0],[-cos((%pi-th)/2)*sqrt(2*E)],[sin((%pi-th)/2)*sqrt(2*E)])
(%i9) a34 : up3b . Gam[mu] . vp4;
(%o9) matrix([cos(th/2)*sqrt(2*E),sin(th/2)*sqrt(2*E),0,0])
. Gam[mu]
. matrix([0],[0],[-cos((%pi-th)/2)*sqrt(2*E)],
[sin((%pi-th)/2)*sqrt(2*E)])
Both a12 and a34 are (in general) complex numbers. Ignoring the factor -e2, the numerator Mn of the transition
amplitude is given by the contraction of the product a12*a34 on the index mu.
(%i10) Mn : mcon (a12*a34,mu);
(%o10) 8*cos(th/2)2*E2
The denominator of the transition amplitude is called s_th and is the 4-vector dot product of the sum of the incident
4-momenta:
(%i11) s_th : VP (p1 + p2,p1 + p2);
(%o11) 4*E2
27
Note that this amplitude is real.
As an aside, in the high energy limit the spinor normalizations are zero. For example:
(%i13) sbar(up1) . up1;
(%o13) 0
If we redefine up1 for the arbitrary energy case, in which mass cannot be neglected, then the normalization becomes
2*m, where m is the mass of the particle.
(%i14)
(%o14)
(%i15)
(%o15)
(%i16)
(%o16)
(%i17)
(%o17)
up1 : UU(E,p,0,0,1);
matrix([sqrt(E-p)],[0],[sqrt(E+p)],[0])
sbar (up1) . up1;
2*sqrt(E-p)*sqrt(E+p)
rootscontract (%);
2*sqrt(E2-p2)
ratsubst (m, sqrt(E2-p2), %);
2 *m
In the massless limit P(+1) picks out negative physical helicity case (sv = -1) if we are dealing with an antiparticle.
(%i20) Mn_sq:(a12:mat_trace(P(1) . sL(p2)
. Gam[mu] . P(1) . sL(p1) . Gam[nu]),
a34:mat_trace(P(1) . sL(p3)
. Gam[mu] . P(1) . sL(p4) . Gam[nu]),
mcon (a12*a34,mu,nu),factor(%%));
(%o20) 16*(cos(th)+1)2*E4
(%i21) time(%);
(%o21) [0.03]
To compare with the absolute value squared of the transition matrix element calculated above using Dirac spinors, we
convert the a function of th/2 using the Dirac package function to_ao2 (expr,a), where the symbol for the angle
must be correctly inserted.
(%i22) Mn_sq : to_ao2 (Mn_sq, th);
(%o22) 64*cos(th/2)4*E4
28
Dividing this numerator squared expression by s_th2, we get what should be the same as Amp_RL_RL2 (since
Amp_RL_RL is real):
(%i23)
(%o23)
(%i24)
(%o24)
M_sq : Mn_sq/s_th2;
4*cos(th/2)4
M_sq - Amp_RL_RL2;
0
Here is the recommended symbolic approach, in which the immediate use of nc_tr allows mcon to do the contraction.
The factor S(sv) --> (1 + sv*G5)/2, effectively, is the massless helicity projection operator for the symbolic
method.
(%i31) Mn_sq:(a12 : nc_tr (S(1),p2,mu,S(1),p1,nu),
a34 : nc_tr (S(1),p3,mu,S(1),p4,nu),
mcon (a12*a34,mu,nu),
factor(%%));
(%o31) -16*(sin(th)2-2*cos(th)-2)*E4
(%i32) time(%);
(%o32) [0.34]
(%i33) Mn_sq : to_ao2 (Mn_sq,th);
(%o33) 64*cos(th/2)4*E4
(%i34) M_sq : Mn_sq/s_th2;
(%o34) 4*cos(th/2)4
(%i35) M_sq - Amp_RL_RL2;
(%o35) 0
In terms of time, the explicit matrix approach (m_tr) to these polarized squared amplitudes is about five times faster than
the nc_tr symbolic approach.
29
Just as an experiment, the non-recommended and slow calculation, in which we apply noncov to the product of two
expressions produced by tr, and then use mcon to contract, looks like this:
(%i36) Mn_sq : (a12 : tr(S(1),p2,mu,S(1),p1,nu),
a34 : tr(S(1),p3,mu,S(1),p4,nu),
noncov (a12*a34),
mcon (%%,mu,nu),factor(%%));
(%o36) -16*(sin(th)2-2*cos(th)-2)*E4
(%i37) time(%);
(%o37) [3.89]
which took about eleven times as long as the recommended nc_tr method. Slightly longer times arise with the explicit
use of econ or Con:
(%i38) Mn_sq : (a12 : tr(S(1),p2,mu,S(1),p1,nu),
a34 : tr(S(1),p3,mu,S(1),p4,nu),
noncov (a12*a34),
econ (%%,mu,nu),factor(%%));
(%o38) -16*(sin(th)2-2*cos(th)-2)*E4
(%i39) time(%);
(%o39) [3.98]
(%i40) Mn_sq : (a12 : tr(S(1),p2,mu,S(1),p1,nu),
a34 : tr(S(1),p3,mu,S(1),p4,nu),
noncov (a12*a34),
Con (%%,mu,nu),factor(%%));
(%o40) -16*(sin(th)2-2*cos(th)-2)*E4
(%i41) time(%);
(%o41) [4.01]
The denominator of the transition amplitude is called s_th (the square of the total CMS energy) and is the 4-vector dot
product of the sum of the incident 4-momenta:
(%i3) s_th : VP (p1 + p2,p1 + p2);
(%o3) 4*E2
30
As in the high energy case, the incident electron has attributes p1,sv1 = 1 and is represented by the spinor up1 (a
column vector), the incident positron has attributes p2, sv2 = -1 and is represented by the barred antiparticle spinor
vp2b (a row vector). The outgoing muon has attributes p3 and sv3 = 1 and is represented by the barred particle spinor
up3b (a row vector), the outgoing antimuon has attributes p4 and sv4 = -1 and is represented by the antiparticle
spinor vp4 (a column vector).
(%i4)
(%o4)
(%i5)
(%o5)
(%i6)
(%i7)
(%o7)
up1 : UU(E,p,0,0,1);
matrix([sqrt(E-p)],[0],[sqrt(E+p)],[0])
vp2b : sbar(VV(E,p,%pi,0,-1));
matrix([0,-sqrt(E+p),0,sqrt(E-p)])
a12 : vp2b . Gam[mu] . up1$
up3b : sbar(UU(E,k,th,0,1));
matrix([cos(th/2)*sqrt(E+k),sin(th/2)*sqrt(E+k),cos(th/2)*sqrt(E-k),
sin(th/2)*sqrt(E-k)])
(%i8) vp4 : VV(E,k,%pi-th,%pi,-1);
(%o8) matrix([cos((%pi-th)/2)*sqrt(E-k)],[-sin((%pi-th)/2)*sqrt(E-k)],
[-cos((%pi-th)/2)*sqrt(E+k)],[sin((%pi-th)/2)*sqrt(E+k)])
(%i9) a34 : up3b . Gam[mu] . vp4$
Both a12 and a34 are (in general) complex numbers. Ignoring the factor -e2, the numerator Mn of the transition amplitude is given by the contraction of the product a12*a34 on the index mu, and, as before, the amplitude Amp_RL_RL
(again, we are ignoring -e2) is Mn/s_th.
(%i10)
(%o10)
(%i11)
(%o11)
Mn : mcon (a12*a34,mu);
8*cos(th/2)2*E2
Amp_RL_RL : Mn/s_th;
2*cos(th/2)2
which is the same as the high energy limit previously discussed for this process.
Trace Methods and Arbitrary Energy Case Helicity Projection Matrices and Operators
The symbol Sp1 is the positive helicity spin 4-vector defined by the incident electron 4-momentum vector p1. The
symbol Sp2 is the positive helicity spin 4-vector defined by the incident positron 4-momentum vector p2. The symbol
Sp3 is the positive helicity spin 4-vector defined by the final muon 4-momentum vector p3. The symbol Sp4 is the
positive helicity spin 4-vector defined by the final antimuon 4-momentum vector p4.
(%i12) tr(S(1,Sp1));
(%o12) 2
(%i13) comp_def(Sp1(p/m,0,0,E/m),
Sp2(p/m,0,0,(-E)/m),
Sp3(k/M,E*sin(th)/M,0,E*cos(th)/M),
Sp4(k/M,(-E*sin(th))/M,0,(-E*cos(th))/M))$
(%i14) p_Em(expr) := expand (ratsubst (E2-m2,p2,expr))$
(%i15) k_EM(expr) := expand (ratsubst (E2-M2,k2,expr))$
In the contraction result, we can simplify by replacing k2 and p2 in terms of the equivalent quantities depending on E
and either m or M.
First the mat_trace method. In the explicit matrix method, a matrix factor P(sv1,Sp1), turns into the matrix
(I4 + sv1*Gam[5].sL(Sp1))/2, in which Sp1 is the positive helicity spin 4-vector implied by the particles
4-momentum p1.
(%i16)
(%o16)
(%i17)
(%o17)
31
The matrix P(sv1,Sp1) is the matrix version of the finite mass spin projection operator, and requires a frame dependent
definition (using comp_def) of the components of the positive helicity spin 4-vector corresponding to a particles 4momentum.
(%i18) a12 : mat_trace(Gam[mu] . P(1,Sp1) . (sL(p1) + m*I4)
. Gam[nu] . P(-1,Sp2) . (sL(p2) - m*I4))$
(%i19) a34 : mat_trace (Gam[mu] . P(-1,Sp4) . (sL(p4) - M*I4)
. Gam[nu] . P(1,Sp3) . (sL(p3) + M*I4))$
(%i20) Mn_sq : (mcon (a12*a34,mu,nu),
k_EM(%%),p_Em(%%),
expand(trigsimp(%%)),factor(%%));
(%o20) 16*(cos(th)+1)2*E4
(%i21) time(%);
(%o21) [0.58]
(%i22) Mn_sq : to_ao2 (Mn_sq, th);
(%o22) 64*cos(th/2)4*E4
(%i23) M_sq : Mn_sq/s_th2;
(%o23) 4*cos(th/2)4
The mat_trace method requires careful attention to parentheses, and it is simpler (and also faster) to use the equivalent
m_tr method, which uses the same operator notation as tr, but actually translates everything into a mat_trace
expression.
(%i24) a12 : m_tr (mu,S(1,Sp1),p1 + m,nu,S(-1,Sp2),p2 - m)$
(%i25) a34 : m_tr (mu,S(-1,Sp4),p4 - M,nu,S(1,Sp3),p3 + M)$
(%i26) Mn_sq : (mcon (a12*a34,mu,nu),
k_EM(%%),p_Em(%%),
expand(trigsimp(%%)),factor(%%));
(%o26) 16*(cos(th)+1)2*E4
(%i27) time(%);
(%o27) [0.59]
(%i28) Mn_sq : to_ao2 (Mn_sq, th);
(%o28) 64*cos(th/2)4*E4
(%i29) M_sq : Mn_sq/s_th2;
(%o29) 4*cos(th/2)4
Finally we use the symbolic nc_tr method, which is a specially designed function which immediately takes noncov
of the trace of each term of the general expansion of the starting expression.
The symbolic method uses the helicity projection operators such as S(sv1,Sp1), used for a particle with helicity
quantum number sv1 = +/- 1 and 4-momentum p1 and corresponding positive helicity spin vector Sp1 defined by
p1. In the symbolic method, a factor S(sv1,Sp1), turns into the symbolic factor
(1 + sv1*G5*Sp1)/2, in which Sp1 is the positive helicity spin 4-vector implied by the particles 4-momentum p1.
(%i36)
(%o36)
(%i37)
(%o37)
(%i38)
(%o38)
(%i39)
(%o39)
(%i40)
(%o40)
(%i41)
(%o41)
tr(S(1,Sp1));
2
tr(S(-1,Sp1));
2
tr(mu,S(1,Sp1));
0
tr(mu,nu,rh,G5,Sp1);
4*%i*Eps(mu,nu,rh,N4)*LI(Sp1,N4)
tr(mu,nu,rh,S(1,Sp1));
2*%i*Eps(mu,nu,rh,N5)*LI(Sp1,N5)
tr(mu,nu,rh,S(-1,Sp1));
-2*%i*Eps(mu,nu,rh,N6)*LI(Sp1,N6)
32
We first populate the list invarR used by the symbolic method for the immediate evaluation of 4-vector dot products
such as D(p1,p1), which is done by tr.
(%i42) invarR;
(%o42) []
(%i43) invar(D(p1,p1) = m2,
D(p2,p2) = m2,
D(p3,p3) = M2,
D(p4,p4) = M2,
D(p1,Sp1) = 0,
D(Sp1,Sp1) = -1,
D(p2,Sp2) = 0,
D(Sp2,Sp2) = -1,
D(p3,Sp3) = 0,
D(Sp3,Sp3) = -1,
D(p4,Sp4) = 0,
D(Sp4,Sp4) = -1)$
(%i44) invarR;
(%o44) [D(Sp4,Sp4) = -1,D(p4,Sp4) = 0,D(Sp3,Sp3) = -1,D(p3,Sp3) = 0,
D(Sp2,Sp2) = -1,D(p2,Sp2) = 0,D(Sp1,Sp1) = -1,D(p1,Sp1) = 0,
D(p4,p4) = M2,D(p3,p3) = M2,D(p2,p2) = m2,D(p1,p1) = m2]
(%i45) Mn_sq:(nc_tr(mu,S(1,Sp1),m+p1,nu,S(-1,Sp2),p2-m),a12:p_Em(%%),
nc_tr(mu,S(-1,Sp4),p4-M,nu,S(1,Sp3),M+p3),a34:k_EM(%%),
mcon(a12*a34,mu,nu),k_EM(%%),p_Em(%%),trigsimp(%%),factor(%%));
(%o45) -16*(sin(th)2-2*cos(th)-2)*E4
(%i46) time(%);
(%o46) [1.43]
(%i47) Mn_sq:to_ao2(Mn_sq,th);
(%o47) 64*cos(th/2)4*E4
(%i48) M_sq:Mn_sq/s_th2;
(%o48) 4*cos(th/2)4
We now proceed to use a batch file method to examine a series of basic simple examples of quantum electrodynamics
using our tools.
+ (p 1 ) + + (p 2 ) + (p 3 ) + + (p 4 )
(12.38)
s = (p 1 + p 2 )2 ,
t = (p 1 p 3 )2 ,
u = (p 1 p 4 )2 ,
(12.39)
The symbolic method is used to derive the unpolarized differential cross section, starting with the invariant amplitude
M = M1 + M2 , in which
e2 (p 1 + p 3 ) (p 2 + p 4 )
M1 =
,
t
(12.40)
e2 (p 1 + p 4 ) (p 2 + p 3 )
.
u
(12.41)
and
M2 =
The Feynman rules for scalar electrodynamics are discussed in: G/R, QED, p. 434 ff, Renton, p.180 ff, I/Z, p. 282 ff,
B/D, RQM, p. 195, Aitchison, p. 51 ff, A/H, p. 158 ff, Kaku, p. 158 ff, Quigg, p. 49, Schwinger, p. 284 ff, H/M, Ch. 4.
33
The list invarR (rules for invariant dot products) is first populated using the Dirac package function invar, which will
be used by tr to replace invariant dot products such as D(p1,p1), D(p1,p2), etc by expressions in terms of the mass
m of the scalar particle, and the Mandelstam variables s, t, u.
We then use comp_def to define the components of the 4-vectors in the center of momentum (CM) frame, and evaluate
the Mandelstam variables in that frame.
Some other Dirac package defined functions used in moller0.mac are take_parts, ev_Ds, pullfac, sub_stu,
and fr_ao2.
The batch file moller0.mac is used after loading in the Dirac package.
(%i1) load(dirac2);
dirac2.mac
simplifying-new.lisp
dgtrace2.mac
dgcon2.mac
dgeval2.mac
dgmatrix2.mac
scalarL = [c1, c2, c3, c4, c5, c6, c7, c8, c9, c10]
indexL = [n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, la, mu, nu, rh, si, ta, al,
be, ga, de, ep]
massL = [m, M]
Nlast = 0
reserved program capital letter name use:
Chi, Con, D, Eps, G, G(1), G5, G5p, Gam, Gm, Gtr, LI, Nlast, UI, P, S, Sig
UU, VP, VV, I2, Z2, CZ2, I4, Z4, CZ4, RZ4, N1,N2,...
reserved array names: gmet, eps4
invar_flag = true
stu_flag = false
(%o1) "c:/work5/dirac2.mac"
(%i2) batch ("moller0.mac");
read and interpret file: #pc:/work5/moller0.mac
(%i3) " ======================================================"
(%i4) " file moller0.mac "
(%i5) " Maxima by Example, Ch. 12 "
(%i6) " Dirac Algebra and Quantum Electrodynamics "
(%i7) " Edwin L Woollett, [email protected] "
(%i8) " http://www.csulb.edu/woollett "
(%i9) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-04
(%i10)
(%i11)
(%i12)
(%i13)
(%i14)
(%i15)
(%i16)
(%i17)
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%i23)
(%i24)
(%o24)
" ======================================================"
" ELASTIC SCATTERING OF SPIN 0 PARTICLES (SAME CHARGE)"
" FOR EXAMPLE: "
"
PI(+,p1) PI(+,p2) ---> PI(+,p3) PI(+,p4)
"
" POPULATE THE LIST invarR OF 4-VEC DOT PRODUCT VALUES, "
" Using p1 + p2 = p3 + p4, s = (p1+p2)2 = (p3+p4)2 ,"
" t = (p1-p3)2 = (p2-p4)2,"
"
and u = (p1-p4)2 = (p2-p3)2 "
" ---------------------------------------------"
invar(D(p1,p1) = m2,D(p1,p2) = s/2-m2,D(p1,p3) = m2-t/2,
D(p1,p4) = m2-u/2,D(p2,p2) = m2,D(p2,p3) = m2-u/2,
D(p2,p4) = m2-t/2,D(p3,p3) = m2,D(p3,p4) = s/2-m2,
D(p4,p4) = m2)
"------------------------------------------------------"
" factor out -e2 from Mfi, leaving Mfi = M1 + M2 "
M1:D(p3+p1,p4+p2)/D(p1-p3,p1-p3)
M2:D(p4+p1,p3+p2)/D(p1-p4,p1-p4)
M1:ev_Ds(M1)
s/t-u/t
34
(%i25)
(%o25)
(%i26)
(%o26)
(%i27)
(%o27)
(%i28)
(%o28)
(%i29)
(%i30)
(%i31)
(%i32)
(%i33)
(%o33)
(%i34)
(%o34)
(%i35)
(%o35)
(%i36)
(%o36)
(%i37)
(%i38)
(%i39)
(%o39)
(%i40)
(%o40)
(%i41)
(%o41)
(%i42)
(%o42)
(%i43)
(%i44)
(%o44)
(%i45)
(%i46)
(%i47)
(%i48)
(%i49)
(%i50)
(%i51)
(%i52)
(%i53)
(%i54)
(%i55)
(%i56)
(%o56)
(%i57)
(%o57)
M1:pullfac(M1,1/t)
(s-u)/t
M2:ev_Ds(M2)
s/u-t/u
M2:pullfac(M2,1/u)
(s-t)/u
Mfi:M2+M1
(s-u)/t+(s-t)/u
" we get the result Mfi = (s-u)/t + (s-t)/u "
"CM FRAME EVALUATION "
assume(p > 0,th >= 0,th <= %pi)
comp_def(p1(E,0,0,p),p2(E,0,0,-p),p3(E,p*sin(th),0,p*cos(th)),
p4(E,-p*sin(th),0,-p*cos(th)))
s_th:noncov(D(p2+p1,p2+p1))
4*E2
t_th:factor(noncov(D(p1-p3,p1-p3)))
2*p2*(cos(th)-1)
u_th:factor(noncov(D(p1-p4,p1-p4)))
-2*p2*(cos(th)+1)
Mfi:sub_stu(Mfi)
-4*E2/(p2*sin(th)2)-4/sin(th)2+2
" We want to combine the first two terms "
" and replace p2 by E2 - m2 in the numerator"
Mfi_12:ratsimp(take_parts(Mfi,1,2))
-(4*E2+4*p2)/(p2*sin(th)2)
Mfi_12n:num(Mfi_12)
-4*E2-4*p2
Mfi_12n:factor(expand(subst(p2 = E2-m2,Mfi_12n)))
-4*(2*E2-m2)
Mfi_12:Mfi_12n/denom(Mfi_12)
-4*(2*E2-m2)/(p2*sin(th)2)
" We now add in the third term and extract -2 "
Mfi:pullfac(part(Mfi,3)+Mfi_12,-2)
-2*(2*(2*E2-m2)/(p2*sin(th)2)-1)
" having absorbed e4 into a factor A which multiplies"
" |Mfi|2, and using e2 = 4*%pi*alpha,"
" in general, A = alpha2*(pf/pi)/(4*Ecm2) "
" but here, pf = pi, and Ecm = 2*E, so "
A:alpha2/(16*E2)
" We can now write down the differential scattering cross section:"
dsigdo:A*Mfi2
(display2d:true,display(dsigdo),display2d:false)
2
2
2 2 (2 E - m )
2
alpha (------------- - 1)
2
2
p sin (th)
dsigdo = --------------------------2
4 E
" which agrees with Itzykson and Zuber, p. 286."
" The factor 1/sin(th)2 can be displayed in terms of th/2"
" using: "
fr_ao2(1/cos(th/2)2+1/sin(th/2)2,th)
4/sin(th)2
" and, of course p2 = E2 - m2 "
"moller0.mac"
35
Since this is the first example of using a batch file to program the calculations, we show here the appearance of the batch
file moller0.mac.
To save space, we will only show the batch file run output for the remaining examples, even though the batch file output is
rather compressed (minimum white space) and symbols are rearranged in the way Maxima likes to organize printed output.
Of course you can edit your own batch file run output to include more white space which would make the results more
readable and easier to follow.
/* file moller0.mac
pi(+) pi(+) --> pi(+) pi(+)
in scalar electrodynamics, ie,
ignoring structure of pions */
"
"
"
"
"
"
"
"
"
"
/* references:
Renton p.182
I/Z p. 286
Schwinger, pp. 285 - 289
*/
======================================================"$
file moller0.mac "$
Maxima by Example, Ch. 12 "$
Dirac Algebra and Quantum Electrodynamics "$
Edwin L Woollett, [email protected] "$
http://www.csulb.edu/woollett "$
print ("
ver: ",_binfo%," date: ",mydate )$
======================================================"$
ELASTIC SCATTERING OF SPIN 0 PARTICLES (SAME CHARGE)"$
FOR EXAMPLE: "$
PI(+,p1) PI(+,p2) ---> PI(+,p3) PI(+,p4)
"$
" POPULATE THE LIST invarR OF 4-VEC DOT PRODUCT VALUES, "$
" Using p1 + p2 = p3 + p4, s = (p1+p2)2 = (p3+p4)2 ,"$
" t = (p1-p3)2 = (p2-p4)2,"$
"
and u = (p1-p4)2 = (p2-p3)2 "$
" ---------------------------------------------"$
invar (D(p1,p1) = m2,
D(p1,p2) = s/2 - m2,
D(p1,p3) = m2 - t/2,
D(p1,p4) = m2 - u/2,
D(p2,p2) = m2,
D(p2,p3) = m2 - u/2,
D(p2,p4) = m2 - t/2,
D(p3,p3) = m2,
D(p3,p4) = s/2 - m2,
D(p4,p4) = m2)$
"------------------------------------------------------"$
" factor out -e2 from Mfi, leaving Mfi = M1 + M2 "$
M1 : D(p1+p3,p2+p4)/D(p1-p3,p1-p3)$
M2 :
D(p1+p4,p2+p3)/D(p1-p4,p1-p4)$
36
M1 : ev_Ds (M1);
M1 : pullfac (M1,1/t);
M2 : ev_Ds (M2);
M2 : pullfac (M2,1/u);
Mfi : M1 + M2;
" we get the result Mfi = (s-u)/t + (s-t)/u
"$
A : alpha2/(16*E2)$
37
" We can now write down the differential scattering cross section:"$
dsigdo : A*Mfi2$
(display2d:true, display (dsigdo), display2d:false)$
" which agrees with Itzykson and Zuber, p. 286."$
" The factor 1/sin(th)2 can be displayed in terms of th/2"$
" using: "$
fr_ao2(1/sin(th/2)2 + 1/cos(th/2)2, th );
" and, of course p2 = E2 - m2 "$
12.6
The batch file moller1.mac treats the high energy limit of the scattering event
(12.42)
We consider the unpolarized ultra-relativistic limit in which the masses of the electrons can be ignored (|p| >> m).
Some references are: C. Moller, 1932, Schwinger, PSF I, p. 300 - 305, Greiner-Reinhardt, QED, 4th, Sec. 3.3, Griffith
Sec. 7.6, Jauch and Rohrlich, p. 252-257, Renton Sec. 4.3.1, B/D Sec. 7.9, BLP, Sec. 81.
(Note that BLPs symbol re should be replaced by /m to compare with our results - they use (along with Greiner/Reinhardt)
Gaussian units for electromagnetic equations, whereas we use (along with Peskin/Schroeder and Bjorken/Drell) rationalized Heaviside-Lorentz electromagnetic units. e2HL = 4 e2G See Greiner/Reinhardt, Sec 4.2.).
The invariant amplitude M = M1 M2 , has two terms. Using the definitions
s = (p 1 + p 2 )2 ,
t = (p 1 p 3 )2 ,
u = (p 1 p 4 )2 ,
(12.43)
u1 = u(p1 , 1 ),
we have
and
u2 = u(p2 , 2 ),
u3 = u(p3 , 3 ),
u4 = u(p4 , 4 )
(12.44)
e2 u3 u1 u4 u2
,
M1 =
t
(12.45)
e2 u4 u1 u3 u2
.
M2 =
u
(12.46)
The unpolarized differential cross section in the CM frame is first found using symbolic methods, first in terms of
s, t, u and then in terms of the scattering angle th.
The polarized amplitudes corresponding to definite electron helicity assignments are then calculated using explicit Dirac
spinors and matrices, and the sum of the squares of these amplitudes reproduces the unpolarized symbolic calculation.
Finally one polarized squared amplitude is calculated using the symbolic methods. We will surpress the information
output which dirac2.mac puts on the screen after loading in the package files.
38
(%i58) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) batch ("moller1.mac");
read and interpret file: #pc:/work5/moller1.mac
(%i3) " ======================================================"
(%i4) " file moller1.mac "
(%i5) " Maxima by Example, Ch. 12 "
(%i6) " Dirac Algebra and Quantum Electrodynamics "
(%i7) " Edwin L Woollett, [email protected] "
(%i8) " http://www.csulb.edu/woollett "
(%i9) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-04
(%i10)
(%i11)
(%i12)
(%i13)
(%i14)
(%i15)
(%i16)
(%i17)
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%i23)
(%i24)
(%i25)
(%i26)
(%i27)
(%i28)
(%i29)
(%i30)
(%o30)
(%i31)
(%o31)
(%i32)
(%i33)
(%i34)
(%o34)
(%i35)
(%o35)
(%i36)
(%o36)
(%i37)
(%i38)
(%i39)
(%i40)
(%i41)
(%o41)
(%i42)
" ======================================================"
"
MOLLER SCATTERING
"
" HIGH ENERGY LIMIT, CENTER OF MOMENTUM FRAME, NEGLECT MASSES "
" e(-,p1,sv1) + e(-,p2,sv2) --> e(-,p3,sv3) + e(-,p4,sv4) "
" m = electron mass is set to zero."
" ------------------------------------------ "
"NON-POLARIZED DIFFERENTIAL CROSS SECTION: SYMBOLIC METHODS"
" POPULATE THE LIST invarR OF 4-VEC DOT PRODUCT VALUES, "
" Using p1 + p2 = p3 + p4, s = (p1+p2)2 = (p3+p4)2 ,"
" t = (p1-p3)2 = (p2-p4)2,"
"
and u = (p1-p4)2 = (p2-p3)2 "
" CASE HIGH ENERGY (HE) LIMIT E >> m "
" ---------------------------------------------"
invar(D(p1,p1) = 0,D(p1,p2) = s/2,D(p1,p3) = (-t)/2,D(p1,p4) = (-u)/2,
D(p2,p2) = 0,D(p2,p3) = (-u)/2,D(p2,p4) = (-t)/2,D(p3,p3) = 0,
D(p3,p4) = s/2,D(p4,p4) = 0)
"------------------------------------------------------"
" factor out -e2 from Mfi, leaving Mfi = M1 - M2 "
" With a sum over all helicities implied,"
" |Mfi|2 = M1n/t2 + M2n/u2 -M12n/(t*u) - M21n/(t*u) "
" M1n = t2 * M1*conj(M1), M2n = u2 * M2*conj(M2) "
" M12n = (t*u)*M1*conj(M2), M21n = (t*u)*M2*conj(M1), and: "
M1n:factor(Con(tr(p3,mu,p1,nu)*tr(p4,mu,p2,nu),mu,nu))
8*(u2+s2)
M2n:factor(Con(tr(p4,mu,p1,nu)*tr(p3,mu,p2,nu),mu,nu))
8*(t2+s2)
" NOTE AUTOMATIC PRETRACE CONTRACTION OF REPEATED "
" LORENTZ INDICES WITHIN A SINGLE TRACE OCCURS USING tr."
M12n:factor(tr(p3,mu,p1,nu,p4,mu,p2,nu))
-8*s2
M21n:factor(tr(p4,mu,p1,nu,p3,mu,p2,nu))
-8*s2
MfiSQ:pullfac((-M21n)/(t*u)+(-M12n)/(t*u)+M2n/u2+M1n/t2,8)
8*((u2+s2)/t2+2*s2/(t*u)+(t2+s2)/u2)
" We have absorbed e4 into A, with e2 = 4*%pi*alpha "
" Averaging over initial spins means we need to divide A by 4"
" to get the unpolarized differential cross section (CM, HE)"
A:alpha2/(4*s)
dsigdo_unpol_CM_HE:A*MfiSQ/4
alpha2*((u2+s2)/t2+2*s2/(t*u)+(t2+s2)/u2)/(2*s)
(display2d:true,display(dsigdo_unpol_CM_HE),display2d:false)
2
2
2
2
2
2 u + s
2 s
t + s
alpha (------- + ---- + -------)
2
t u
2
t
u
dsigdo_unpol_CM_HE = --------------------------------2 s
39
(%i43)
(%i44)
(%i45)
(%i46)
(%i47)
40
(%i73)
(%i74)
(%o74)
(%i75)
(%o75)
(%i76)
(%o76)
(%i77)
(%o77)
(%i78)
(%i79) " which agrees with G/R, page 139, top. "
The next section of moller1.mac uses explicit Dirac spinors and matrices to calculate polarized amplitudes.
(%i80)
(%i81)
(%i82)
(%i83)
(%i84)
(%i85)
" --------------------------------------------------"
" HE POLARIZED AMPLITUDES USING EXPLICIT DIRAC SPINORS "
" ------------------------------------------------- "
" case HE RR --> RR, ie, (+1,+1) --> (+1,+1) polarized amplitude "
" Define the needed Dirac spinors and barred spinors."
(up1:UU(E,E,0,0,1),up3b:sbar(UU(E,E,th,0,1)),up2:UU(E,E,%pi,0,1),
up4b:sbar(UU(E,E,%pi-th,%pi,1)))
(%i86) " For example, following Halzen/Martin p. 120 ff :"
(%i87) " For helicity quantum numbers RR -> RR, the amplitude Mfi"
(%i88) " (pulling out -e2) has the form Mfi = M1 - M2 "
(%i89) " where M1 = Mt/t and M2 = Mu/u, "
(%i90) " where t = (p1-p3)2 and u = (p1-p4)2, and "
(%i91) Mt:(a13:up3b . Gam[mu] . up1,a24:up4b . Gam[mu] . up2,mcon(a13*a24,mu),
trigsimp(%%))
(%o91) -8*E2
(%i92) Mu:(a14:up4b . Gam[mu] . up1,a23:up3b . Gam[mu] . up2,mcon(a14*a23,mu),
trigsimp(%%))
(%o92) 8*E2
(%i93) Mfi:Mt/t-Mu/u
(%o93) -8*E2/u-8*E2/t
(%i94) " Now replace s, t, and u by explicit functions of th "
(%i95) Mfi:sub_stu(Mfi)
(%o95) -8/(cos(th)2-1)
(%i96) Mfi_RR_RR:ts(Mfi,th)
(%o96) 8/sin(th)2
(%i97) " Now automate production of HE polarized amplitudes "
(%i98) " as functions of t and u "
(%i99) " Our definition of the amplitude does not include a factor of -e2."
(%i100) he_me(sp1v,sp2v,sp3v,sp4v):=block([up1,up2,up3b,up4b,_mu%,Mt,Mu,temp],
up1:UU(E,E,0,0,sp1v),up3b:sbar(UU(E,E,th,0,sp3v)),
up2:UU(E,E,%pi,0,sp2v),up4b:sbar(UU(E,E,%pi-th,%pi,sp4v)),
a13:up3b . Gam[_mu%] . up1,a24:up4b . Gam[_mu%] . up2,
Mt:(Con(a13*a24,_mu%),expand(trigsimp(%%)))/t,
a14:up4b . Gam[_mu%] . up1,a23:up3b . Gam[_mu%] . up2,
Mu:(Con(a14*a23,_mu%),expand(trigsimp(%%)))/u,temp:Mt-Mu,
if temp # 0 then temp:pullfac(temp,-8*E2),temp)
(%i101) " test he_me for the case already worked out above "
(%i102) he_me(1,1,1,1)
(%o102) -8*(1/u+1/t)*E2
(%i103) sub_stu(%)
(%o103) -8/(cos(th)2-1)
41
(%i104)
(%o104)
(%i105)
(%i106)
(%i107)
(%i108)
(%i109)
(%i110)
(%i111)
(%i112)
(%i113)
(%i114)
(%i115)
(%i116)
(%i117)
(%i118)
ts(%,th)
8/sin(th)2
" which agrees with our previous work."
" ---------------------------------------- "
" AN ALTERNATIVE PATH TO THE UNPOLARIZED CROSS SECTION "
" IS TO SUM THE ABSOLUTE VALUE SQUARED OF EACH "
" OF THE POLARIZED AMPLITUDES, WHICH WE NOW DO."
" The function Avsq(expr) is defined in dgmatrix.mac "
" and computes the absolute value squared."
" (We could also use here abs(expr)2 )"
" Each nonzero amplitude is proportional to 8*E2*e2"
" here since we have not replaced t or u in the denominators"
" by a function of th."
" We have already pulled out -e2 from our amplitude def"
" Pull out also the factor 8*E2 temporarily here."
block([sL,s1,s2,s3,s4,temp],sL:[1,-1],mssq:0,print(" "),
print(" svp1 svp2 svp3 svp4
amplitude
"),print("
for s1 in sL do
for s2 in sL do
for s3 in sL do
for s4 in sL do
(temp:expand(he_me(s1,s2,s3,s4)/(8*E2)),
mssq:Avsq(temp)+mssq,print(" "),
print(s1,s2,s3,s4," ",temp)),
mssq:expand(fr_ao2(mssq,th)))
svp1 svp2
1 1 1 1
svp3
svp4
amplitude
-1/u-1/t
1 1 1 -1
1 1 -1 1
1 1 -1 -1
1 -1 1 1
0
0
1 -1 1 -1
cos(th/2)2/t
1 -1 -1 1
sin(th/2)2/u
1 -1 -1 -1
-1 1 1 1
0
0
-1 1 1 -1
sin(th/2)2/u
-1 1 -1 1
cos(th/2)2/t
-1 1 -1 -1
-1 -1 1 1
0
0
-1 -1 1 -1
-1 -1 -1 1
-1 -1 -1 -1
-1/u-1/t
(%i119) " -------------------------------------- "
"),
42
(%i120) mssq
(%o120) 4/(t*u)+cos(th)2/(2*u2)-cos(th)/u2+5/(2*u2)+cos(th)2/(2*t2)
+cos(th)/t2+5/(2*t2)
(%i121) mssq:sub_stu(mssq)
(%o121) cos(th)4/(4*sin(th)4*E4)+3*cos(th)2/(2*sin(th)4*E4)
+9/(4*sin(th)4*E4)
(%i122) mssq:factor(ratsimp(mssq))
(%o122) (cos(th)2+3)2/(4*sin(th)4*E4)
(%i123) " restore (8*E2)2 = 64*E4 to mssq "
(%i124) mssq:64*E4*mssq
(%o124) 16*(cos(th)2+3)2/sin(th)4
(%i125) dsigdo_unpol_CM_HE:A*mssq/4
(%o125) alpha2*(cos(th)2+3)2/(s*sin(th)4)
(%i126) dsigdo_unpol_CM_HE:subst(s = s_th,%)
(%o126) alpha2*(cos(th)2+3)2/(4*sin(th)4*E2)
(%i127) (display2d:true,display(dsigdo_unpol_CM_HE),display2d:false)
2
2
2
alpha (cos (th) + 3)
dsigdo_unpol_CM_HE = ---------------------4
2
4 sin (th) E
(%i128) " which agrees with the symbolic calculation."
The last section of moller1.mac uses symbolic methods to find the square of polarized amplitudes. An argument
S(1) or S(-1) inside tr is effectively interpreted as 12 (1 + 5 ), where = 1 is the argument of S.
(%i129)
(%i130)
(%i131)
(%i132)
(%i133)
(%i134)
(%i135)
(%o135)
(%i136)
(%o136)
(%i137)
(%i138)
(%i139)
(%o139)
(%i140)
(%o140)
(%i141)
(%o141)
(%i142)
(%o142)
(%i143)
(%o144)
43
12.7
The batch file moller2.mac works out the case of arbitrary energy particles in the CM frame. See the references and
kinematic notation in the previous section dealing with moller1.mac.
The first section of moller2.mac works out the unpolarized differential cross section for arbitrary energy, first in an
arbitrary frame in terms of s, t, u, and then in the CM frame, using symbolic methods.
(%i145) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) batch ("moller2.mac");
read and interpret file: #pc:/work5/moller2.mac
(%i3) " ======================================================"
(%i4) " file moller2.mac "
(%i5) " Maxima by Example, Ch. 12 "
(%i6) " Dirac Algebra and Quantum Electrodynamics "
(%i7) " Edwin L Woollett, [email protected] "
(%i8) " http://www.csulb.edu/woollett "
(%i9) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-04
(%i10)
(%i11)
(%i12)
(%i13)
(%i14)
(%i15)
(%i16)
(%i17)
(%i18)
(%o18)
(%i19)
(%o19)
(%i20)
(%i21)
(%i22)
(%o22)
(%i23)
(%o23)
(%i24)
(%i25)
(%o25)
(%i26)
(%i27)
(%i28)
(%i29)
(%i30)
(%o30)
(%i31)
(%o31)
(%i32)
(%o32)
(%i33)
(%i34)
(%o34)
"
MOLLER SCATTERING
"
"
ARBITRARY ENERGY, CENTER OF MOMENTUM FRAME "
" e(-,p1,sv1) + e(-,p2,sv2) --> e(-,p3,sv3) + e(-,p4,sv4) "
" ------------------------------------------ "
" SYMBOLIC TRACES FOR UNPOLARIZED DIFFERENTIAL CROSS SECTION "
" Supply s, t, and u expressions for dot products "
" ---------------------------------------------- "
invar(D(p1,p1) = m2,D(p1,p2) = s/2-m2,D(p1,p3) = m2-t/2,
D(p1,p4) = m2-u/2,D(p2,p2) = m2,D(p2,p3) = m2-u/2,
D(p2,p4) = m2-t/2,D(p3,p3) = m2,D(p3,p4) = s/2-m2,
D(p4,p4) = m2)
M1n:Con(tr(m+p3,mu,m+p1,nu)*tr(m+p4,mu,m+p2,nu),mu,nu)
8*u2-32*m2*u+32*m2*t+8*s2-32*m2*s+64*m4
M2n:Con(tr(m+p4,mu,m+p1,nu)*tr(m+p3,mu,m+p2,nu),mu,nu)
32*m2*u+8*t2-32*m2*t+8*s2-32*m2*s+64*m4
" NOTE AUTOMATIC PRETRACE CONTRACTION OF REPEATED "
" LORENTZ INDICES WITHIN A SINGLE TRACE OCCURS USING tr."
M12n:tr(m+p3,mu,m+p1,nu,m+p4,mu,m+p2,nu)
-16*m2*u-16*m2*t-8*s2+48*m2*s-32*m4
M21n:tr(m+p4,mu,m+p1,nu,m+p3,mu,m+p2,nu)
-16*m2*u-16*m2*t-8*s2+48*m2*s-32*m4
" expressed as a function of s, t, and u "
MfiSQ:(-M21n)/(t*u)+(-M12n)/(t*u)+M2n/u2+M1n/t2
(8*u2-32*m2*u+32*m2*t+8*s2-32*m2*s+64*m4)/t2
+(32*m2*u+8*t2-32*m2*t+8*s2-32*m2*s+64*m4)/u2
+2*(16*m2*u+16*m2*t+8*s2-48*m2*s+32*m4)/(t*u)
" REPLACE s, t, and u WITH EXPLICIT FUNCTIONS OF th "
" ------------------------------------------------- "
assume(E > 0,p > 0,th >= 0,th <= %pi)
comp_def(p1(E,0,0,p),p2(E,0,0,-p),p3(E,p*sin(th),0,p*cos(th)),
p4(E,-p*sin(th),0,-p*cos(th)))
s_th:VP(p2+p1,p2+p1)
4*E2
t_th:factor(VP(p1-p3,p1-p3))
2*p2*(cos(th)-1)
u_th:factor(VP(p1-p4,p1-p4))
-2*p2*(cos(th)+1)
" ------------------------------------------------- "
MfiSQ_th:factor(trigsimp(sub_stu(MfiSQ)))
16*(8*E4+2*m2*cos(th)2*E2-10*m2*E2+p4*cos(th)4+6*p4*cos(th)2
+10*m2*p2*cos(th)2+m4*cos(th)2+p4-2*m2*p2+3*m4)
/(p4*sin(th)4)
44
The next section of moller2.mac uses explicit Dirac spinors and matrices to calculate polarized amplitudes.
(%i47)
(%i48)
(%i49)
(%i50)
(%i51)
(%i52)
(%i53)
(%i54)
(%i55)
(%i56)
(%o56)
(%i57)
(%o57)
(%i58)
(%i59)
(%i60)
" ========================================================="
" POLARIZED DIRAC SPINOR AMPLITUDES
"
" ---------------------------------------------------------"
E_pm(expr):=expand(ratsubst(m2+p2,E2,expr))
p_Em(expr):=expand(ratsubst(E2-m2,p2,expr))
Ep_m(expr):=expand(ratsubst(m,sqrt(E-p)*sqrt(p+E),expr))
Ep_Mm(expr):=(expand(ratsubst(M2/4-m2,p2,expr)),
expand(ratsubst(M/2,E,%%)))
" -----------------------------------------------"
" convert t_th and u_th to th/2 forms "
t_th2:to_ao2(t_th,th)
-4*p2*sin(th/2)2
u_th2:to_ao2(u_th,th)
-4*p2*cos(th/2)2
" dirac spinor amplitude given global s1,s2,s3,s4 "
dA():=(
(up1:UU(E,p,0,0,s1),up3b:sbar(UU(E,p,th,0,s3)),up2:UU(E,p,%pi,0,s2),
up4b:sbar(UU(E,p,%pi-th,%pi,s4))),
Mt:(a13:up3b . Gam[mu] . up1,a24:up4b . Gam[mu] . up2,
mcon(a13*a24,mu)),Mt:Ep_m(Mt),M1:Mt/t_th2,
Mu:(a14:up4b . Gam[mu] . up1,a23:up3b . Gam[mu] . up2,
mcon(a14*a23,mu)),Mu:Ep_m(Mu),M2:Mu/u_th2,Mfi:M1-M2)
" Print a table of polarized amplitudes."
45
1 1 1 1
svp3
svp4
amplitude
m2*sin(th/2)2/(p2*cos(th/2)2)+2*sin(th/2)2/cos(th/2)2
+m2*cos(th/2)2/(p2*sin(th/2)2)
+2*cos(th/2)2/sin(th/2)2+4
1 1 1 -1
m*sin(th/2)*E/(p2*cos(th/2))-m*cos(th/2)*E/(p2*sin(th/2))
1 1 -1 1
m*sin(th/2)*E/(p2*cos(th/2))-m*cos(th/2)*E/(p2*sin(th/2))
1 1 -1 -1
1 -1 1 1
2*m2/p2
m*cos(th/2)*E/(p2*sin(th/2))-m*sin(th/2)*E/(p2*cos(th/2))
1 -1 1 -1
m2*cos(th/2)2/(p2*sin(th/2)2)+2*cos(th/2)2/sin(th/2)2-m2/p2
1 -1 -1 1
m2*sin(th/2)2/(p2*cos(th/2)2)+2*sin(th/2)2/cos(th/2)2-m2/p2
1 -1 -1 -1
-1 1 1 1
m*sin(th/2)*E/(p2*cos(th/2))-m*cos(th/2)*E/(p2*sin(th/2))
m*cos(th/2)*E/(p2*sin(th/2))-m*sin(th/2)*E/(p2*cos(th/2))
-1 1 1 -1
m2*sin(th/2)2/(p2*cos(th/2)2)+2*sin(th/2)2/cos(th/2)2-m2/p2
-1 1 -1 1
m2*cos(th/2)2/(p2*sin(th/2)2)+2*cos(th/2)2/sin(th/2)2-m2/p2
-1 1 -1 -1
-1 -1 1 1
m*sin(th/2)*E/(p2*cos(th/2))-m*cos(th/2)*E/(p2*sin(th/2))
2*m2/p2
-1 -1 1 -1
m*cos(th/2)*E/(p2*sin(th/2))-m*sin(th/2)*E/(p2*cos(th/2))
-1 -1 -1 1
m*cos(th/2)*E/(p2*sin(th/2))-m*sin(th/2)*E/(p2*cos(th/2))
-1 -1 -1 -1
m2*sin(th/2)2/(p2*cos(th/2)2)+2*sin(th/2)2/cos(th/2)2
+m2*cos(th/2)2/(p2*sin(th/2)2)
+2*cos(th/2)2/sin(th/2)2+4
(%i63) mssq
(%o63) -192*m2/(p2*sin(th)2)-48*m4/(p4*sin(th)2)-128/sin(th)2
+256*m2/(p2*sin(th)4)+64*m4/(p4*sin(th)4)
+256/sin(th)4+16
(%i64) " SHOW THIS IS THE SAME AS MfiSQ_th computed above with traces "
(%i65) MfiSQ_p:E_pm(MfiSQ_th)
(%o65) 16*cos(th)4/sin(th)4+192*m2*cos(th)2/(p2*sin(th)4)
+48*m4*cos(th)2/(p4*sin(th)4)
+96*cos(th)2/sin(th)4+64*m2/(p2*sin(th)4)
+16*m4/(p4*sin(th)4)+144/sin(th)4
(%i66) trigsimp(mssq-MfiSQ_p)
(%o66) 0
46
12.8
This batch file treats the high energy limit of the scattering event
(12.47)
This limit is that in which the masses of the particles can be ignored (|p| >> m). In practice this means treating the
leptons as massless particles.
Some references are: H.J. Bhabha, 1936, BLP QED, Sec. 81, B/D RQM, Sec. 7.9, G/R QED, Sec. 3.4, Renton EI, Sec.
4.3, and Schwinger, PSF I, p. 306 - 309.
The invariant amplitude M = M1 M2 has two terms. Using the definitions
s = (p 1 + p 2 )2 ,
t = (p 1 p 3 )2 ,
u = (p 1 p 4 )2 ,
(12.48)
u1 = u(p 1 , 1 ),
we have
and
v4 = v(p 4 , 4 ),
u3 = u(p 3 , 3 ),
v2 = v(p 2 , 2 )
(12.49)
e2 u3 u1 v2 v4
M1 =
,
t
(12.50)
e2 v2 u1 u3 v4
M2 =
.
s
(12.51)
The batch file bhabha1.mac uses the Dirac package functions pullfac, VP, to_ao2, Avsq, and fr_ao2.
The first section of bhabha1.mac derives the unpolarized differential cross section, first in an arbitrary frame in terms
of s, t, u, and then in the CM frame in terms of the scattering angle th, using symbolic methods.
(%i69) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) batch ("bhabha1.mac");
read and interpret file: #pc:/work5/bhabha1.mac
(%i3) " ======================================================"
(%i4) " file bhabha1.mac "
(%i5) " Maxima by Example, Ch. 12 "
(%i6) " Dirac Algebra and Quantum Electrodynamics "
(%i7) " Edwin L Woollett, [email protected] "
(%i8) " http://www.csulb.edu/woollett "
(%i9) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-04
(%i10)
(%i11)
(%i12)
(%i13)
(%i14)
"
BHABHA SCATTERING
"
" HIGH ENERGY LIMIT, CENTER OF MOMENTUM FRAME, NEGLECT MASSES "
" e(-,p1,s1) + e(+,p2,s2) --> e(-,p3,s3) + e(+,p4,s4) "
" m = electron and positron mass is set to zero."
" ------------------------------------------ "
47
(%i15)
(%i16)
(%i17)
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%i23)
(%i24)
(%i25)
(%i26)
(%i27)
(%i28)
(%o28)
(%i29)
(%o29)
(%i30)
(%i31)
(%i32)
(%o32)
(%i33)
(%o33)
(%i34)
(%o34)
(%i35)
(%i36)
(%i37)
(%i38)
(%i39)
(%o39)
(%i40)
(%i41)
(%i42)
(%i43)
(%i44)
(%i45)
(%i46)
(%o46)
(%i47)
(%o47)
(%i48)
(%o48)
(%i49)
(%i50)
(%i51)
(%o51)
(%i52)
(%o52)
(%i53)
(%o53)
48
(%i54) (display2d:true,display(dsigdo_unpol_th),display2d:false)
2
2
2
alpha (cos (th) + 3)
dsigdo_unpol_th = ---------------------2 2
16 (cos(th) - 1) E
(%i55) "------------------------------------------------------------"
(%i56) " which agrees with Renton, p. 160 "
The next section of bhabha1.mac uses explicit Dirac spinors and matrices to compute the polarized amplitudes.
(%i57)
(%i58)
(%i59)
(%o59)
(%i60)
(%i61)
(%i62)
(%i63)
(%i64)
(%o64)
(%i65)
(%i66)
(%i67)
" HIGH ENERGY POLARIZED AMPLITUDES USING EXPLICIT DIRAC SPINORS "
" ------------------------------------------------- "
t_th2:to_ao2(t_th,th)
-4*sin(th/2)2*E2
" dirac spinor amplitude given global s1,s2,s3,s4 "
dA():=(
(up1:UU(E,E,0,0,s1),up3b:sbar(UU(E,E,th,0,s3)),
vp2b:sbar(VV(E,E,%pi,0,s2)),vp4:VV(E,E,%pi-th,%pi,s4)),
Mt:(a13:up3b . Gam[_mu%] . up1,a42:vp2b . Gam[_mu%] . vp4,
mcon(a13*a42,_mu%),expand(trigsimp(%%))),M1:Mt/t_th2,
Ms:(a12:vp2b . Gam[_mu%] . up1,a43:up3b . Gam[_mu%] . vp4,
mcon(a12*a43,_mu%),expand(trigsimp(%%))),M2:Ms/s_th,M1-M2)
" example: RR --> RR "
[s1,s2,s3,s4]:[1,1,1,1]
dA()
2/sin(th/2)2
" Make table of polarized amplitudes. "
" Accumulate sum mssq of square of amplitudes."
block([sL,sv1,sv2,sv3,sv4,temp],sL:[1,-1],mssq:0,print(" "),
print(" s1 s2 s3 s4
amplitude
"),print(" "),
for sv1 in sL do
for sv2 in sL do
for sv3 in sL do
for sv4 in sL do
([s1,s2,s3,s4]:[sv1,sv2,sv3,sv4],temp:dA(),
mssq:Avsq(temp)+mssq,print(" "),
print(s1,s2,s3,s4,"
",temp)),
mssq:expand(fr_ao2(mssq,th)))
s1 s2
s3
1 1 1 1
s4
amplitude
2/sin(th/2)2
1 1 1 -1
1 1 -1 1
1 1 -1 -1
1 -1 1 1
0
0
1 -1 1 -1
2*cos(th/2)2/sin(th/2)2-2*cos(th/2)2
1 -1 -1 1
-2*sin(th/2)2
1 -1 -1 -1
-1 1 1 1
0
0
49
-1 1 1 -1
-2*sin(th/2)2
-1 1 -1 1
2*cos(th/2)2/sin(th/2)2-2*cos(th/2)2
-1 1 -1 -1
-1 -1 1 1
0
0
-1 -1 1 -1
-1 -1 -1 1
-1 -1 -1 -1
2/sin(th/2)2
(%i68) " Sum of squares of polarized amplitudes:"
(%i69) mssq
(%o69) 4*cos(th)4/(cos(th)2-2*cos(th)+1)
+24*cos(th)2/(cos(th)2-2*cos(th)+1)+36/(cos(th)2-2*cos(th)+1)
(%i70) " COMPARE WITH SYMBOLIC RESULT MfiSQ_th CALCULATED ABOVE"
(%i71) trigsimp(mssq-MfiSQ_th)
(%o71) 0
(%i72) " WHICH SHOWS THEY ARE EQUIVALENT."
(%o72) "bhabha1.mac"
"
50
(%i13)
(%i14)
(%i15)
(%i16)
(%i17)
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%o22)
(%i23)
(%o23)
(%i24)
(%i25)
(%i26)
(%o26)
(%i27)
(%o27)
(%i28)
(%i29)
(%o29)
(%i30)
(%i31)
(%i32)
(%i33)
(%i34)
(%o34)
(%i35)
(%o35)
(%i36)
(%o36)
(%i37)
(%i38)
(%i39)
(%i40)
(%i41)
(%o41)
(%i42)
(%i43)
(%i44)
(%o44)
(%i45)
(%o45)
(%i46)
(%o46)
(%i47)
(%i48)
(%i49)
(%i50)
(%i51)
51
(%i52)
(%o52)
(%i53)
(%i54)
(%i55)
(%i56)
(%i57)
(%i58)
(%i59)
(%i60)
(%i61)
trigsimp(GR-MfiSQ_p/4)
0
" which shows the equivalence we need "
" dividing MfiSQ by 4 comes from averaging over"
" the initial helicities "
" We have absorbed e4 into A, with e2 = 4*%pi*alpha "
" to get the unpolarized differential cross section (CM)"
A:alpha2/(4*s_th)
GR_expr:GR3+GR2+GR1
dsigdo_unpol_CM:A*GR_expr
(display2d:true,display(dsigdo_unpol_CM),display2d:false)
4
4 th
2 2
2 th
4
- 4 p cos (--) - 8 m p cos (--) - 3 m
2
2
2
dsigdo_unpol_CM = (alpha (----------------------------------------2
2 th
2
p sin (--) E
2
4
2
2 2
4
p (cos (th) + 1) + 4 m p + 3 m
+ ---------------------------------4
E
4
4 th
2 2
2 th
4
2 p (cos (--) + 1) + 4 m p cos (--) + m
2
2
2
+ -------------------------------------------))/(16 E )
4
4 th
p sin (--)
2
(%i62) " which agrees with G/R, Exer. 3.8, eqn. 21, p. 148 "
The next section of bhabha2.mac uses explicit Dirac spinors and matrices to compute polarized amplitudes.
(%i63)
(%i64)
(%i65)
(%i66)
(%i67)
(%i68)
(%i69)
(%i70)
(%i71)
(%o71)
(%i72)
(%i73)
(%i74)
(%i75)
(%o75)
(%i76)
(%o76)
52
s2
s3
1 1 1 1
s4
amplitude
(4*m2-8*m2*sin(th/2)2)/(4*E2)+(-4*m2*cos(th/2)2-8*p2)
/(4*p2*sin(th/2)2)
1 1 1 -1
2*m*cos(th/2)*sin(th/2)/E-m*cos(th/2)*E/(p2*sin(th/2))
1 1 -1 1
m*cos(th/2)*E/(p2*sin(th/2))-2*m*cos(th/2)*sin(th/2)/E
1 1 -1 -1
1 -1 1 1
(4*m2-8*m2*sin(th/2)2)/(4*E2)+m2/p2
m*cos(th/2)*E/(p2*sin(th/2))-2*m*cos(th/2)*sin(th/2)/E
1 -1 1 -1
(8*p2+8*m2)*cos(th/2)2/(4*E2)+(-8*p2-4*m2)*cos(th/2)2
/(4*p2*sin(th/2)2)
1 -1 -1 1
(8*p2+8*m2)*sin(th/2)2/(4*E2)-m2/p2
1 -1 -1 -1
-1 1 1 1
m*cos(th/2)*E/(p2*sin(th/2))-2*m*cos(th/2)*sin(th/2)/E
2*m*cos(th/2)*sin(th/2)/E-m*cos(th/2)*E/(p2*sin(th/2))
-1 1 1 -1
(8*p2+8*m2)*sin(th/2)2/(4*E2)-m2/p2
-1 1 -1 1
(8*p2+8*m2)*cos(th/2)2/(4*E2)+(-8*p2-4*m2)*cos(th/2)2
/(4*p2*sin(th/2)2)
-1 1 -1 -1
-1 -1 1 1
2*m*cos(th/2)*sin(th/2)/E-m*cos(th/2)*E/(p2*sin(th/2))
(4*m2-8*m2*sin(th/2)2)/(4*E2)+m2/p2
-1 -1 1 -1
2*m*cos(th/2)*sin(th/2)/E-m*cos(th/2)*E/(p2*sin(th/2))
-1 -1 -1 1
m*cos(th/2)*E/(p2*sin(th/2))-2*m*cos(th/2)*sin(th/2)/E
-1 -1 -1 -1
(%i80)
(%i81)
(%i82)
(%o82)
(%i83)
(%i84)
(4*m2-8*m2*sin(th/2)2)/(4*E2)+(-4*m2*cos(th/2)2-8*p2)
/(4*p2*sin(th/2)2)
"------------------------------------------"
" sum of squares of polarized amplitudes:"
mssq
(4*p8*sin(th)4+(-8*m2*p6*cos(th)-32*p8-72*m2*p6-52*m4*p4)
*sin(th)2+(32*m2*p6+80*m4*p4+56*m6*p2)*cos(th)
+64*p8+160*m2*p6+128*m4*p4+40*m6*p2+16*m8)
/((p8+2*m2*p6+m4*p4)*cos(th)2
+(-2*p8-4*m2*p6-2*m4*p4)*cos(th)+p8+2*m2*p6+m4*p4)
" SHOW THIS IS THE SAME AS MfiSQ_th computed above with traces "
MfiSQ_p:E_pm(MfiSQ_th)
53
(%i85)
(%o85)
(%i86)
(%i87)
(%o88)
12.10
trigsimp(mssq-MfiSQ_p)
0
" which shows equality."
" =========================================================== "
"bhabha2.mac"
In this section we use Maxima to work out some well known properties of photon polarization 3-vectors corresponding to
physical (external) photons, using the batch file photon1.mac. Some references to this subject are: G/R QED p. 187,
Weinberg I p. 352, 360, 368, Renton p. 166, and Gross p. 315.
Let ek s be a real photon polarization 3-vector which is transverse to the initial photon 3-momentum k, with s = 1 being
parallel to the scattering plane, and s = 2 being perpendicular to the scattering plane.
Let ek0 r be a real photon polarization 3-vector which is transverse to the final photon 3-momentum k0 with r = 1 being
parallel to the scattering plane, and r = 2 being perpendicular to the scattering plane. Then we have the relations
2
X
ek0 r
(ek s ek0 r ) = 1 k
2
(12.52)
s=1
2
X
s,r=1
Here we are using real polarization 3-vectors to describe states of linear polarization.
(%i89) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) batch ("photon1.mac");
read and interpret file: #pc:/work5/photon1.mac
(%i3) display2d:false
(%i4) " ======================================================"
(%i5) " file photon1.mac "
(%i6) " Maxima by Example, Ch. 12 "
(%i7) " Dirac Algebra and Quantum Electrodynamics "
(%i8) " Edwin L Woollett, [email protected] "
(%i9) " http://www.csulb.edu/woollett "
(%i10) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-04
(%i11)
(%i12)
(%i13)
(%i14)
(%i15)
(%i16)
(%i17)
(%i18)
(%i19)
(%i20)
(%o20)
(%i21)
(%o21)
(%i22)
"-----------------------------------------------------"
" PROPERTIES AND SUMS OF TRANSVERSE POLARIZATION VECTORS "
" ----------------------------------------------------- "
" define 3-vectors as lists "
" scattering plane is z-x plane "
k_vec:[0,0,k]
kp_vec:[kp*sin(th),0,kp*cos(th)]
" e[1] X e[2] = k_vec/k "
e[1]:[1,0,0]
e[1] . e[1]
1
e[1] . k_vec
0
e[2]:[0,1,0]
(12.53)
54
(%i23)
(%o23)
(%i24)
(%o24)
(%i25)
(%o25)
(%i26)
(%i27)
(%i28)
(%i29)
(%o29)
(%i30)
(%o30)
(%i31)
(%i32)
(%i33)
(%o33)
(%i34)
(%o34)
(%i35)
(%o35)
(%i36)
(%i37)
(%i38)
(%i39)
(%o39)
(%i40)
(%i41)
(%i42)
(%i43)
(%i44)
(%o44)
(%i45)
(%i46)
(%o46)
(%i47)
(%o47)
(%i48)
(%i49)
(%o49)
(%i50)
(%o50)
(%i51)
(%o51)
12.11
e[2] . e[2]
1
e[2] . e[1]
0
e[2] . k_vec
0
" ep[1] X ep[2] = kp_vec/kp "
" parallel to the scattering plane "
ep[1]:[cos(th),0,-sin(th)]
trigsimp(ep[1] . ep[1])
1
ep[1] . kp_vec
0
" perpendicular to the scattering plane "
ep[2]:[0,1,0]
ep[2] . ep[2]
1
ep[2] . ep[1]
0
ep[2] . kp_vec
0
"============================================="
" photon transverse polarization sum over both leads to "
" (1 + cos(th)2 ) "
sum(sum((e[s] . ep[r])2,s,1,2),r,1,2)
cos(th)2+1
"============================================="
" Sum over only e[1] and e[2] values leads to "
" sum ( (e[s] . ep[r])2,s,1,2) = 1 - (ku . ep[r])2 "
" where ku is unit vector along k_vec "
ku:k_vec/k
[0,0,1]
" first for r = 1 "
sum((e[s] . ep[1])2,s,1,2)
cos(th)2
trigsimp(1-(ku . ep[1])2)
cos(th)2
" next for r = 2 "
sum((e[s] . ep[2])2,s,1,2)
1
1-(ku . ep[2])2
1
"============================================="
"photon1.mac"
We will use the following relation for covariant physical photon polarization 4-vectors which are 4-orthogonal to the
photon 4-momentum vector. This formalism (Sterman, p. 220, De Wit/Smith, p.141, Schwinger, p. 73 and pp. 291 - 294,
Jauch/Rohrlich, p. 440) uses gauge freedom within the Lorentz gauge.
The two physical polarization states of real external photons corresond to = 1, 2, and for , = 0, 1, 2, 3,
P (k) =
X
=1,2
ek ek = g +
(k k + k k )
,
k k
= (k 0 , k).
where there exists a reference frame in which if k = (k 0 , k) then k
(12.54)
55
k = k + 2 n (k n).
(12.55)
ek ek 0 = 0 ,
, 0 = 1, 2
(12.56)
An alternative but less compact form of the physical photon polarization tensor P (k) is
P (k) =
ek ek = g
=1,2
k k
(k n + k n )
+
(k n)2
kn
(12.57)
We can always identify the unit timelike 4-vector n with either the total 4-momentum vector (thus working in the CM
frame) or the 4-momentum of a particular particle (thus working in the rest frame of that particle).
Thus if in a chosen frame, {p } = {m, 0, 0, 0}, we identify n = p /m, so that {n } = {1, 0, 0, 0}, then in that
0 = k 0 and kj = k j .
frame k
Then n ek = 0 implies that e0k = 0, and then k ek = 0 reduces to k ek = 0 (for = 1, 2), and the two
polarization 3-vectors ek must be chosen perpendicular to k and to each other: ek 1 ek 2 = 0.
12.12
In this section we use the batch file compton0.mac to work out details of Compton scattering of scalar charged particles. Some references to this subject can be found in G/R QED, p 435, B/D RQM, p. 193, Schwinger PSF I, p290,
Aitchison RQM, p87, De Wit/Smith, p 147, I/Z p. 286.
Three diagrams contribute to Compton scattering of a scalar charged particle which we can for convenience think of as
(12.58)
Let
s = (k1 + p1 )2 ,
t = (k1 k2 )2 ,
u = (k1 p2 )2 .
(12.59)
Four momentum conservation means p1 + k1 = p2 + k2 . If we ignore a factor e2 and use real photon polarization
4-vectors, the invariant amplitude is
M=
ek2 2
(2 p2 + k2 ) (2 p1 + k1 ) (2 p1 k2 ) (2 p2 k1 )
2 g
ek1 1 (12.60)
s m2
u m2
M = 2 ek2 2 T ek1 1
where
T = g
p2 p1 p2 p1
+
k1 p 1
k1 p 2
(12.61)
(12.62)
X
2
(12.63)
56
Using the compact form of P (k2 ), only the first term contributes at this stage. The second term contribution is
proportional to
k2 T = (k2 + p2 p1 ) = k1
(12.64)
But then k1 ek1 1 = 0. Likewise the third term contribution is zero because k2 T = k1 , and k1 ek1 1 = 0.
We now sum over 1 .
|M |2 = 4 T P (k1 ) T = 4 (T T 2) ,
(12.65)
1 , 2
T k1
k1 T / k1 k1 .
= k1 , as we saw above.
In the compton0.mac code, the expression T is represented by t_munu, written in terms of the constructs D, UI,
and Gm which the Dirac package recognises. The contraction T T becomes Con (t_munu2).
The batch file compton0.mac uses the Dirac package functions VP and ev_Ds.
(%i3) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) batch ("compton0.mac");
read and interpret file: #pc:/work5/compton0.mac
(%i3) " ======================================================"
(%i4) " file compton0.mac "
(%i5) " Maxima by Example, Ch. 12 "
(%i6) " Dirac Algebra and Quantum Electrodynamics "
(%i7) " Edwin L Woollett, [email protected] "
(%i8) " http://www.csulb.edu/woollett "
(%i9) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-04
(%i10)
(%i11)
(%i12)
(%i13)
(%i14)
(%i15)
(%i16)
(%i17)
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%i23)
(%i24)
(%i25)
57
58
(%i75) (display2d:true,display(dsigdo_lab_unpol),display2d:false)
2
2
2
alpha kp (cos (th) + 1)
dsigdo_lab_unpol = ------------------------2 2
2 k m
(%i76)
(%i77)
(%i78)
(%i79)
(%i80)
(%i81)
(%i82)
(%i83)
(%i84)
(%i85)
(%i86)
(%i87)
(%i88)
(%i89)
(%i90)
(%i91)
"
"
"
"
"
"
"
59
(%i110)
(%i111)
(%i112)
(%i113)
(%i114)
(%i115)
(%i116)
(%i117)
(%o117)
12.13
"----------------------------------------------------------------"
" If we only average over the polarization of the incident photon"
" and leave the polarization of the final photon arbitrary, we "
" replace (1+cos(th)2) by ( 1 - dot(ku,e2_vec)2) which gives "
" 1 for e2_vec chosen perpendicular to the scattering plane, and "
" gives sin(th)2 for e2_vec chosen parallel to the scattering "
" plane, leading to the scattered photons polarized preferentially"
" in a direction perpendicular to the scattering plane."
"compton0.mac"
(12.66)
M1 =
u2 1 u1
,
u m2
and
M2 =
u2 2 u1
,
s m2
u = (p1 k2 )2
s = (p1 + k1 )2
(12.67)
(12.68)
The first section of compton1.mac calculates the unpolarized differential cross section, proportional to
|M1 + M2 |2 .
(12.69)
1 , 2 , 1 , 2
u2 /e1 a u1 u1 b /e1 u2 =
ek1 1 ek1 1
u2 a u1 u1 b u2
(12.70)
A convenient, simplifying feature of the lepton photon interaction is that only the first (metric tensor) term of P (k1 )
need be retained, since the other terms produce zero contribution (as is discussed in quantum field theory texts). Thus for
lepton photon interactions we effectively have
P (k1 ) g
(12.71)
u2 a u1 u1 b u2 .
(12.72)
X
1 , 2 , 1 , 2
(12.73)
TheP
compton1.mac code uses the symbol m1sq for the trace in the numerator, and uses the symbol Mssq_unpol
for
|M1 + M2 |2 (see also the run line (%i32)). The Dirac package functions VP, D_sub, take_parts,ts, and
pullfac are used in this code.
60
(%i1) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) batch("compton1.mac");
file_search1: compton1.mac not found in file_search_maxima.
-- an error. To debug this try: debugmode(true);
(%i3) batch("compton1.mac");
read and interpret file: #pc:/work5/compton1.mac
(%i4) " ======================================================"
(%i5) " file compton1.mac "
(%i6) " Maxima by Example, Ch. 12 "
(%i7) " Dirac Algebra and Quantum Electrodynamics "
(%i8) " Edwin L Woollett, [email protected] "
(%i9) " http://www.csulb.edu/woollett "
(%i10) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-04
(%i11)
(%i12)
(%i13)
(%i14)
(%i15)
(%i16)
(%i17)
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%i23)
(%i24)
(%i25)
(%i26)
(%o26)
(%i27)
(%o27)
(%i28)
(%o28)
(%i29)
(%o29)
(%i30)
(%o30)
(%i31)
(%i32)
(%i33)
(%i34)
(%i35)
(%i36)
(%i37)
(%i38)
(%i39)
(%i40)
(%o40)
(%i41)
(%i42)
(%o42)
" --------------------------------------------"
"
UNPOLARIZED LEPTON - PHOTON SCATTERING "
" for example : "
" ---------------------------------------------"
" e(-,p1,m) + gamma(k1) --> e(-,p2,m) + gamma(k2) "
" ----------------------------------------------"
"
Arbitrary Frame Covariant Symbolic Methods "
" in an arb frame, D(k1,p1) = D(k2,p2) "
"
and D(k1,p2) = D(k2,p1) "
" In an arbitrary frame we can express everything "
" in terms of m2, D(k1,p1) and D(k2,p1) "
" with a view to then evaluating in the rest frame"
" of the initial electron: p1 = (m,0,0,0) (lab frame) "
" ---------------------------------------------"
invar(D(p1,p1) = m2,D(p2,p2) = m2,D(k1,k1) = 0,D(k2,k2) = 0,
D(p1,p2) = -D(k2,p1)+D(k1,p1)+m2,D(k1,p2) = D(k2,p1),
D(k2,p2) = D(k1,p1),D(k1,k2) = D(k1,p1)-D(k2,p1))
m1sq:tr(m+p2,mu,m-k2+p1,nu,m+p1,nu,m-k2+p1,mu)
32*m4-32*D(k2,p1)*m2+32*D(k1,p1)*D(k2,p1)
m2sq:tr(m+p2,mu,m+k1+p1,nu,m+p1,nu,m+k1+p1,mu)
32*m4+32*D(k1,p1)*m2+32*D(k1,p1)*D(k2,p1)
m1m2sq:tr(m+p2,mu,m-k2+p1,nu,m+p1,mu,m+k1+p1,nu)
32*m4-16*D(k2,p1)*m2+16*D(k1,p1)*m2
m2m1sq:tr(m+p2,mu,m+k1+p1,nu,m+p1,mu,m-k2+p1,nu)
32*m4-16*D(k2,p1)*m2+16*D(k1,p1)*m2
m1m2sq-m2m1sq
0
" The interference terms are equal, so "
" -----------------------------------------------"
" Form the expression :"
" Mssq_unpol = m1sq/(u-m2)2 + m2sq/(s-m2)2 "
"
+ 2*m1m2sq/((u-m2)*(s-m2)), "
"
with u-m2 = -2*D(k2,p1), s-m2 = 2*D(k1,p1), "
"
using u = (p1 - k2)2, s = (p1 + k1)2 "
" ( we use sloppy notation p2 for D(p,p) here )"
" -----------------------------------------------"
Mssq_unpol:expand((-2*m1m2sq)/(4*D(k2,p1)*D(k1,p1))
+m2sq/(4*D(k1,p1)2)+m1sq/(4*D(k2,p1)2))
-16*m4/(D(k1,p1)*D(k2,p1))+8*m4/D(k2,p1)2+8*m4/D(k1,p1)2
-16*m2/D(k2,p1)+16*m2/D(k1,p1)
+8*D(k2,p1)/D(k1,p1)+8*D(k1,p1)/D(k2,p1)
" pull factor of 8 out of definition "
Mssq_unpol8:expand(Mssq_unpol/8)
-2*m4/(D(k1,p1)*D(k2,p1))+m4/D(k2,p1)2+m4/D(k1,p1)2-2*m2/D(k2,p1)
+2*m2/D(k1,p1)+D(k2,p1)/D(k1,p1)
+D(k1,p1)/D(k2,p1)
61
(%i43)
(%i44)
(%i45)
(%i46)
(%i47)
(%i48)
(%i49)
(%i50)
(%o50)
(%i51)
(%i52)
(%i53)
(%i54)
(%o54)
(%i55)
(%o55)
(%i56)
(%o56)
(%i57)
(%o57)
(%i58)
(%o58)
(%i59)
(%i60)
(%o60)
(%i61)
(%i62)
(%o62)
(%i63)
(%o63)
(%i64)
(%i65)
(%i66)
(%i67)
(%i68)
(%i69)
"---------------------------------------------------------"
"
LAB FRAME EVALUATION UNPOLARIZED
"
"
rest frame of initial electron
"
" --------------------------------------------------------"
assume(m > 0,k > 0,kp > 0,th >= 0,th <= %pi)
comp_def(p1(m,0,0,0),k1(k,0,0,k),k2(kp,kp*sin(th),0,kp*cos(th)),
p2(-kp+k+m,-kp*sin(th),0,k-kp*cos(th)))
" use conservation of 4-momentum to find kp "
kp_rule:solve(VP(-k2+k1+p1,-k2+k1+p1) = ev_invar(D(p2,p2)),kp)
[kp = -k*m/(k*cos(th)-m-k)]
" To compare results, only replace kp in terms 1-5 "
" leave kp alone in terms 6-7 "
" D_sub (e,[D1,D2,..] uses noncov on each D(p1,p2) in list"
M1t5:take_parts(Mssq_unpol8,1,5)
-2*m4/(D(k1,p1)*D(k2,p1))+m4/D(k2,p1)2+m4/D(k1,p1)2-2*m2/D(k2,p1)
+2*m2/D(k1,p1)
M6t7:take_parts(Mssq_unpol8,6,7)
D(k2,p1)/D(k1,p1)+D(k1,p1)/D(k2,p1)
M6t7:D_sub(M6t7,[D(k1,p1),D(k2,p1)])
kp/k+k/kp
M1t5:D_sub(M1t5,[D(k1,p1),D(k2,p1)])
-2*m2/(k*kp)+m2/kp2+m2/k2-2*m/kp+2*m/k
M1t5:trigsimp(ev(M1t5,kp_rule))
cos(th)2-1
" ts is our alternative trigsimp function "
M1t5:ts(M1t5,th)
-sin(th)2
" restore overall factor of 8 "
Mssq_unpol:8*(M6t7+M1t5)
8*(-sin(th)2+kp/k+k/kp)
A:alpha2*(kp/k)2/(4*m2)
alpha2*kp2/(4*k2*m2)
" -------------------------------------- "
" To get unpolarized differential cross section, "
" divide sum over spins Mssq_unpol by 4 from average "
" over spin of initial electron and initial photon. "
dsigdo_lab_unpol:A*Mssq_unpol/4
(display2d:true,display(dsigdo_lab_unpol),display2d:false)
2
2
2
kp
k
alpha kp (- sin (th) + -- + --)
k
kp
dsigdo_lab_unpol = --------------------------------2 2
2 k m
To calculate the differential cross section for given photon (linear) polarizations (but summing over the inital and final
elecron helicities), we retain the photon polarization vector factors /ek1 1 and /ek2 2 inside the trace created by summing
over the electron helicities.
We already have the basic defining inner products ek1 1 ek1 1 = 1, k1 ek1 1 = 0, ek2 2 ek2 2 = 1, and
k2 ek2 2 = 0.
Since we want a result appropriate to the rest frame of the initial electron p1 , we identify n = p1 /m so that the components of n are (1, 0, 0, 0).
Then n ek1 1 = 0 implies that e0k1 1 = 0 and n ek2 2 = 0 implies that e0k2 2 = 0.
62
Then ek1 1 = (0, ek1 1 ) and ek2 2 = (0, ek2 2 ).
Since the components of p1 are (m, 0, 0, 0), we then have p1 ek1 1 = 0 and p1 ek2 2 = 0. And using 4-momentum
conservation, the former equation implies 0 = ek1 1 (k2 + p2 k1 ), and hence ek1 1 p2 = ek1 1 k2 .
Finally we replace ek2 2 p2 = ek2 2 k1 , using again 4-momentum conservation and the previous relations.
In our code, e1 stands for ek1 1 and e2 stands for ek2 2 .
(%i71)
(%i72)
(%i73)
(%i74)
(%i75)
(%i76)
(%i77)
(%i78)
(%i79)
(%i80)
(%i81)
(%i82)
(%i83)
(%o83)
(%i84)
(%o84)
(%i85)
(%o85)
(%i86)
(%o86)
(%i87)
(%o87)
(%i88)
(%i89)
(%o89)
(%i90)
(%i91)
(%i92)
(%i93)
(%o93)
(%i94)
(%o94)
(%i95)
(%i96)
(%i97)
(%i98)
"======================================================"
"----UNPOLARIZED ELECTRONS, POLARIZED PHOTONS ------------"
"------- rest frame of initial electron p1 ------------- "
" Leave photon polarization 4-vectors e1,e2 in trace. "
" replace p1 dot products using p1 rest frame choice."
" replace p2 dot products with e1,e2 "
"
using 4-mom conservation relation. "
" The D(p1,e1) and D(p1,e2) replacements depend on our "
"
p1 rest frame choice."
" Recall that D has property symmetric, so "
" D(a,b) = D(b,a). "
invar(D(e1,e1) = -1,D(k1,e1) = 0,D(e2,e2) = -1,D(k2,e2) = 0,
D(p1,e1) = 0,D(p1,e2) = 0,D(e1,p2) = -D(e1,k2),
D(e2,p2) = D(e2,k1))
M1sq:tr(m+p2,e1,m-k2+p1,e2,m+p1,e2,m-k2+p1,e1)
8*D(k1,p1)*D(k2,p1)-16*D(e1,k2)2*D(k2,p1)
M2sq:tr(m+p2,e2,m+k1+p1,e1,m+p1,e1,m+k1+p1,e2)
8*D(k1,p1)*D(k2,p1)+16*D(e2,k1)2*D(k1,p1)
M1m2sq:tr(m+p2,e1,m-k2+p1,e2,m+p1,e1,m+k1+p1,e2)
-16*D(e1,e2)2*D(k1,p1)*D(k2,p1)+8*D(k1,p1)*D(k2,p1)
+8*D(e2,k1)2*D(k2,p1)
-8*D(e1,k2)2*D(k1,p1)
M2m1sq:tr(m+p2,e2,m+k1+p1,e1,m+p1,e2,m-k2+p1,e1)
-16*D(e1,e2)2*D(k1,p1)*D(k2,p1)+8*D(k1,p1)*D(k2,p1)
+8*D(e2,k1)2*D(k2,p1)
-8*D(e1,k2)2*D(k1,p1)
M2m1sq-M1m2sq
0
" The interference terms are equal, so "
Mssq_pol:expand((-2*M1m2sq)/(4*D(k2,p1)*D(k1,p1))
+M2sq/(4*D(k1,p1)2)+M1sq/(4*D(k2,p1)2))
2*D(k2,p1)/D(k1,p1)+2*D(k1,p1)/D(k2,p1)+8*D(e1,e2)2-4
" avoid use of noncov(D(e1,e2)) which would expand D(e1,e2)"
" in terms of undefined components, by instead using ev"
" or D_sub for selected replacements. "
Mssq_pol:D_sub(Mssq_pol,[D(k1,p1),D(k2,p1)])
2*kp/k+2*k/kp+8*D(e1,e2)2-4
Mssq_pol:pullfac(Mssq_pol,2)
2*(kp/k+k/kp+4*D(e1,e2)2-2)
"To get electron unpolarized, photon polarized differential cross section,"
" divide Mssq_pol by 2 from average over helicity of initial electron. "
dsigdo_lab_pol:A*Mssq_pol/2
(display2d:true,display(dsigdo_lab_pol),display2d:false)
2
2 kp
k
2
alpha kp (-- + -- + 4 D (e1, e2) - 2)
k
kp
dsigdo_lab_pol = --------------------------------------2 2
4 k m
(%i99) " which agrees with the Klein-Nishina form quoted by Weinberg (8.7.39)"
63
(%i100)
(%i101)
(%i102)
(%i103)
(%i104)
(%i105)
(%i106)
(%i107)
(%i108)
(%i109)
(%i110)
(%i111)
"============================================================"
" Now assume unpolarized initial photon. Average the "
" polarized photon dsigdo(r,s) over the two possible values "
" of r which specifies the transverse polarization "
" vector of incident photon e1_vec. With nmu = (1,0,0,0)"
" D(e1,e2)2 --> { dot3 (e1_vec,e2_vec) }2 "
" and sum (D(e1(r),e2(s))2,r,1,2) --> 1 - {dot3(ku,e2_vec(s)}2"
" with ku = unit 3-vector along the z axis, dot3(a,b) = 3-vec dot prod. "
" and dsigdo(s) = sum(dsigdo(r,s),r,1,2)/2 "
" The overall result is recovered with: "
dsigdo_s:subst(4*D(e1,e2)2 = 2-2*dot3(ku,e2_vec)2,dsigdo_lab_pol)
(display2d:true,display(dsigdo_s),display2d:false)
2
2
2
kp
k
alpha kp (- 2 dot3 (ku, e2_vec) + -- + --)
k
kp
dsigdo_s = -------------------------------------------2 2
4 k m
(%i112)
(%i113)
(%i114)
(%i115)
(%i116)
(%o116)
"---------------------------------------------------------"
" which agrees with Weinberg (8.7.40) "
" Summing the above over the two possible values of "
" final photon polarization s then leads to our "
" unpolarized result above "
"compton1.mac"
12.14
(12.74)
s = (p1 + p2 )2 ,
t = (p1 k1 )2 ,
u = (p1 k2 )2 ,
(12.75)
u1 = u(p1 , 1 ),
M = M1 + M2 , with
and
v2 = v(p2 , 2 ),
e1 = ek1 ,1 ,
e2 = ek2 ,2 ,
(12.76)
(12.77)
(12.78)
Some references for this calculation are Griffith p. 241, G/R QED: (p. 192 rest frame of electron, p. 198 CM frame), P/S
p. 168, BLP p. 370, Schwinger p. 314, Kaku p. 170, I/Z p. 230, and B/D p. 132.
The batch file pair1.mac works out the unpolarized differential cross section first in an arbitrary frame, and then in
the CM frame. To compare our result with G/R in the CM frame, we express the result in terms of (E,v), where
p = E*v, E2 = m2 + p2, with v (the dimensionless velocity of either of the incident leptons relative to the
CM frame) having values 0 v < 1.
The Dirac package functions D_sub and ts are used.
64
(%i117) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) batch ("pair1.mac");
read and interpret file: #pc:/work5/pair1.mac
(%i3) " ======================================================"
(%i4) " file pair1.mac "
(%i5) " Maxima by Example, Ch. 12 "
(%i6) " Dirac Algebra and Quantum Electrodynamics "
(%i7) " Edwin L Woollett, [email protected] "
(%i8) " http://www.csulb.edu/woollett "
(%i9) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-04
(%i10)
(%i11)
(%i12)
(%i13)
(%i14)
(%i15)
(%i16)
(%i17)
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%i23)
(%i24)
(%i25)
(%i26)
(%i27)
(%i28)
(%i29)
(%i30)
(%i31)
(%o31)
(%i32)
(%o32)
(%i33)
(%o33)
(%i34)
(%o34)
(%i35)
(%o35)
(%i36)
(%o36)
(%i37)
(%i38)
(%o38)
(%i39)
" --------------------------------------------"
"
UNPOLARIZED PAIR ANNIHILATION
"
" ---------------------------------------------"
" e(-,p1) + e(+,p2) --> gamma(k1) + gamma(k2) "
" ----------------------------------------------"
"
Arbitrary Frame Covariant Symbolic Methods "
" ---------------------------------------------"
" POPULATE THE LIST invarR OF 4-VEC DOT PRODUCT VALUES. "
" Express 4-vector dot products in terms of t, u, and m2 "
" Using s = (p1+p2)2 = (k1+k2)2, t = (p1-k1)2 = "
" (k2-p2)2, u = (p1-k2)2 = (k1-p2)2, s + t + u = 2*m2 "
" ---------------------------------------------------"
invar(D(p1,p1) = m2,D(p1,k1) = (m2-t)/2,D(p1,k2) = (m2-u)/2,
D(p1,p2) = (-(u+t))/2,D(p2,p2) = m2,D(p2,k1) = (m2-u)/2,
D(p2,k2) = (m2-t)/2,D(k1,k1) = 0,D(k1,k2) = m2-(u+t)/2,
D(k2,k2) = 0)
"------------------------------------------------------"
" sum |M|2 over spins of electrons and polarizations "
"
of the photons, which leads to the expression: "
" -------------------------------------------------"
"
m1sq/(t-m2)2 + m2sq/(u-m2)2 +
"
"
(m1m2sq+m2m1sq)/((t-m2)*(u-m2))"
" -------------------------------------------------"
" -where (ignoring e4) --"
m1sq:tr(p2-m,mu,m-k1+p1,nu,m+p1,nu,m-k1+p1,mu)
8*t*u-8*m2*u-24*m2*t-8*m4
m2sq:tr(p2-m,mu,m-k2+p1,nu,m+p1,nu,m-k2+p1,mu)
8*t*u-24*m2*u-8*m2*t-8*m4
m1m2sq:tr(p2-m,mu,m-k1+p1,nu,m+p1,mu,m-k2+p1,nu)
-8*m2*u-8*m2*t-16*m4
m2m1sq:tr(p2-m,mu,m-k2+p1,nu,m+p1,mu,m-k1+p1,nu)
-8*m2*u-8*m2*t-16*m4
m1m2sq-m2m1sq
0
Mssq:ratsimp(2*m1m2sq/((t-m2)*(u-m2))+m2sq/(u-m2)2+m1sq/(t-m2)2)
((8*t-8*m2)*u3+(24*m4-56*m2*t)*u2+(8*t3-56*m2*t2+112*m4*t)*u
-8*m2*t3+24*m4*t2-48*m8)
/((t2-2*m2*t+m4)*u2+(-2*m2*t2+4*m4*t-2*m6)*u+m4*t2-2*m6*t
+m8)
"----- replace t and u in terms of dot products in arb frame ------ "
Mssq_dot:expand(subst([t = m2-2*D(k1,p1),u = m2-2*D(k2,p1)],Mssq))
-16*m4/(D(k1,p1)*D(k2,p1))-8*m4/D(k2,p1)2-8*m4/D(k1,p1)2
+16*m2/D(k2,p1)+16*m2/D(k1,p1)
+8*D(k2,p1)/D(k1,p1)+8*D(k1,p1)/D(k2,p1)
"=================================================="
65
(%i40)
(%i41)
(%i42)
(%i43)
(%i44)
(%i45)
(%i46)
(%i47)
(%i48)
(%i49)
(%i50)
66
(%i76) " which agrees with Greiner and Reinhardt, p.201, eqn (17)"
(%i77) "----------------------------------------------------------"
(%o77) "pair1.mac"
12.15
(12.79)
s = (p1 + p2 )2 ,
t = (p1 k1 )2 ,
u = (p1 k2 )2 .
(12.80)
If we use explicit Dirac spinors and matrices and photon polarization 3-vectors to calculate polarized amplitudes in which
both the leptons and photons have definite helicities in the CM frame, we start with the polarized amplitude already written down in the previous section dealing with pair1.mac.
With the abbreviations
u1 = u(p1 , 1 ),
M = M1 + M2 , with
and
v2 = v(p2 , 2 ),
e1 = ek1 ,1 ,
e2 = ek2 ,2 ,
(12.81)
(12.82)
(12.83)
Here we use explicit Dirac spinor methods in the CM frame, letting each lepton have the energy E = M/2, with M the
total CM frame energy, and then each lepton has 3-momentum magnitude p = E*v = M*v/2. We also have the dimensionless lepton CM frame speed v = sqrt( 1 - 4*m2/M2 ). Each outgoing photon has energy k = M/2
and each photon has 3-momentum magnitude k.
We use the photon polarization conventions of F. Gross. (See Franz Gross, Rel. Q. Mech. and Fld. Theory, pages 54,
218, and Schwinger, PSF I, Sec. 3-13-98.)
The outgoing photons are chosen to be travelling along the +z and z axes. We let e(
z , ) be the photon polarization
3-vector describing a photon travelling in the +z direction, with = 1 being a positive helicity state and = 1 being
a negative helicity state. Then
and
1
e(
z , 1) = (
x + i y),
2
(12.84)
1
e(
z , 1) = (
x i y).
2
(12.85)
We let e(
z , ) be the photon polarization 3-vector describing a photon travelling in the z direction, with = 1 being
a positive helicity state and = 1 being a negative helicity state. Then
1
e(
z , 1) = (
x i y) = Ry () e(
z , 1),
2
(12.86)
67
and
1
e(
z , 1) = (
x + i y) = Ry () e(
z , 1).
2
(12.87)
For our calculation, since the photons are in the final state, we need complex conjugates of these. The first example
discussed is RR --> RR, which means two right-handed electrons (actually positive helicity) turn into two positive
helicity photons. For this first example, we define CM frame components with the line:
comp_def(p1(M/2,M*v*sin(th)/2,0,M*v*cos(th)/2),k1(M/2,0,0,M/2),
k2(M/2,0,0,(-M)/2),e1_cc(0,(-1)/sqrt(2),%i/sqrt(2),0),
e2_cc(0,1/sqrt(2),%i/sqrt(2),0))
which shows that the photon with 4-momentum k1 is travelling along the positive z axis, and the polarization state of this
photon is described by the 4-vector e1_cc with the components (0,(-1)/sqrt(2),%i/sqrt(2),0) in which the
three spatial components agree with e(
z , 1) .
Likewise, the photon with 4-momentum k2 is travelling along the negative z axis, and the symbol e2_cc is the 4vector describing its positive helicity state, with components (0,1/sqrt(2),%i/sqrt(2),0) whose spatial components agree with e(
z , 1) .
The cases considered are RR --> RR, RR --> LL, RR --> RL, RR --> LR, RL --> RL, RL --> LR, and
RL --> RR (this last case has amplitude equal to zero).
Since we want to compare our results with Schwingers results, some involved manipulations are necessary in each
case to arrive at a comparable form.
(%i78) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) batch ("pair2.mac");
read and interpret file: #pc:/work5/pair2.mac
(%i3) " ======================================================"
(%i4) " file pair2.mac "
(%i5) " Maxima by Example, Ch. 12 "
(%i6) " Dirac Algebra and Quantum Electrodynamics "
(%i7) " Edwin L Woollett, [email protected] "
(%i8) " http://www.csulb.edu/woollett "
(%i9) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-04
(%i10)
(%i11)
(%i12)
(%i13)
(%i14)
(%i15)
(%i16)
(%i17)
(%i18)
(%i19)
(%i20)
(%i21)
(%i22)
(%i23)
(%i24)
(%i25)
(%i26)
(%i27)
(%i28)
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
"
--------------------------------------------"
POLARIZED PAIR ANNIHILATION in CM Frame
"
---------------------------------------------"
e(-,p1) + e(+,p2) --> gamma(k1) + gamma(k2) "
----------------------------------------------"
AMPLITUDES USING EXPLICIT DIRAC SPINORS
"
----------------------------------------------"
Define the needed Dirac spinors and barred spinors. "
For example, RR --> RR amplitude without the factor e2, and"
either t-m2 or u-m2 in the denominator . The photon 3-momenta"
magnitudes are equal to M/2, where M = 2*E = CM frame energy."
M >= 2*m, and low energy corresponds to M at its lower limit,"
for which v is close to value 0, and high energy corresponds"
to M >> m, for which v approaches its maximum value 1 "
The lepton 3-momentum magnitudes are each equal to E*v = M*v/2 "
where v is the dimensionless velocity with "
v2 = p2/E2 = (E2-m2)/E2 = 1- 4*m2/M2 "
All particle energies are equal to M/2."
----------------------------------------------------"
68
(%i29)
(%i30)
(%i31)
(%i32)
(%i33)
(%i34)
(%i35)
(%i36)
(%i37)
(%i38)
(%i39)
(%i40)
(%i41)
(%i42)
(%i43)
(%i44)
(%i45)
(%i46)
(%i47)
(%i48)
(%i49)
(%i50)
(%i51)
(%i52)
(%o52)
(%i53)
(%o53)
(%i54)
(%o54)
(%i55)
(%o55)
(%i56)
(%i57)
(%o57)
(%i58)
(%o58)
(%i59)
(%o59)
(%i60)
(%o60)
(%i61)
(%o61)
(%i62)
(%o62)
(%i63)
(%o63)
(%i64)
69
70
71
(%i115)
(%i116)
(%i117)
(%i118)
(%i119)
(%i120)
(%o120)
(%i121)
(%i122)
(%i123)
(%o123)
(%i124)
(%o124)
(%i125)
(%i126)
(%i127)
(%o127)
(%i128)
(%o128)
(%i129)
(%o129)
(%i130)
(%o130)
(%i131)
(%o131)
(%i132)
(%i133)
(%i134)
(%o134)
(%i135)
(%o135)
(%i136)
(%o136)
(%i137)
(%o137)
(%i138)
(%o138)
(%i139)
(%i140)
(%i141)
(%o141)
(%i142)
(%o142)
(%i143)
(%i144)
(%i145)
(%i146)
(%i147)
(%i148)
" ------------------------------------------------"
"----------------------------------------------"
"CASE: e(-,p1,+1) e(+,p2,+1) --> gamma(k1,-1) gamma(k2,+1) "
" -------------------------------------------------"
comp_def(e1_cc(0,1/sqrt(2),%i/sqrt(2),0),
e2_cc(0,1/sqrt(2),%i/sqrt(2),0))
72
(%i149)
(%o149)
(%i150)
(%o150)
(%i151)
(%i152)
(%i153)
(%o153)
(%i154)
(%o154)
(%i155)
(%i156)
(%i157)
(%i158)
(%o158)
(%i159)
(%o159)
(%i160)
(%o160)
(%i161)
(%o161)
(%i162)
(%o162)
(%i163)
(%i164)
(%i165)
(%o165)
(%i166)
(%o166)
(%i167)
(%o167)
(%i168)
(%o168)
(%i169)
(%o169)
(%i170)
(%i171)
(%o171)
(%i172)
(%o172)
(%i173)
listarray(e1_cc)
[0,1/sqrt(2),%i/sqrt(2),0]
listarray(e2_cc)
[0,1/sqrt(2),%i/sqrt(2),0]
" the spinors and denominators are the same "
" recompute the g1 and g2 matrices "
g1:sL(e2_cc) . (m*I4-sL(k1)+sL(p1)) . sL(e1_cc)
matrix([0,0,0,sin(th)*v*M],[0,0,0,0],[0,-sin(th)*v*M,0,0],[0,0,0,0])
g2:sL(e1_cc) . (m*I4-sL(k2)+sL(p1)) . sL(e2_cc)
matrix([0,0,0,sin(th)*v*M],[0,0,0,0],[0,-sin(th)*v*M,0,0],[0,0,0,0])
" ------------------------------------"
" ------------------------------------"
" M1 = Mtn/Mtd "
Mtn:vp2b . g1 . up1
-2*sin((%pi-th)/2)*sin(th/2)*sin(th)*v*M*sqrt(-(v-1)*M/2)
*sqrt((v+1)*M/2)
expand(ratsubst(cos(th/2),sin((%pi-th)/2),%))
-cos(th/2)*sin(th/2)*sin(th)*sqrt(1-v)*v*sqrt(v+1)*M2
expand(ratsubst(2*m/M,sqrt(1-v2),rootscontract(%)))
-2*m*cos(th/2)*sin(th/2)*sin(th)*v*M
Mtn:ratsubst(sin(th)/2,cos(th/2)*sin(th/2),%)
-m*sin(th)2*v*M
M1:Mtn/Mtd
2*m*sin(th)2*v/((1-cos(th)*v)*M)
"------------------------------"
" M2 = Mun/Mud "
Mun:vp2b . g2 . up1
-2*sin((%pi-th)/2)*sin(th/2)*sin(th)*v*M*sqrt(-(v-1)*M/2)
*sqrt((v+1)*M/2)
expand(ratsubst(cos(th/2),sin((%pi-th)/2),%))
-cos(th/2)*sin(th/2)*sin(th)*sqrt(1-v)*v*sqrt(v+1)*M2
expand(ratsubst(2*m/M,sqrt(1-v2),rootscontract(%)))
-2*m*cos(th/2)*sin(th/2)*sin(th)*v*M
Mun:ratsubst(sin(th)/2,cos(th/2)*sin(th/2),%)
-m*sin(th)2*v*M
M2:Mun/Mud
2*m*sin(th)2*v/((cos(th)*v+1)*M)
" --------------------------------"
Mfi:trigsimp(M2+M1)
-4*m*sin(th)2*v/((cos(th)2*v2-1)*M)
Mfi:num(Mfi)/pullfac(expand(denom(Mfi)),-M)
4*m*sin(th)2*v/((1-cos(th)2*v2)*M)
(display2d:true,
disp("CASE: e(-,p1,+1) e(+,p2,+1) --> gamma(k1,-1) gamma(k2,+1) "),
display(Mfi),display2d:false)
CASE: e(-,p1,+1) e(+,p2,+1) --> gamma(k1,-1) gamma(k2,+1)
2
4 m sin (th) v
Mfi = ------------------2
2
(1 - cos (th) v ) M
(%i174)
(%i175)
(%i176)
(%i177)
(%i178)
(%i179)
(%i180)
" ------------------------------------------------"
" Schwingers amplitude for these last two cases differs by a minus sign "
" ----------------------------------------------- "
" CASES LEPTONS HAVE OPPOSITE HELICITIES: see Schwinger (3-13-97). "
"----------------------------------------------"
"CASE: e(-,p1,+1) e(+,p2,-1) --> gamma(k1,+1) gamma(k2,-1) "
" -------------------------------------------------"
73
(%i181)
(%i182)
(%i183)
(%i184)
(%i185)
(%i186)
(%o186)
(%i187)
(%o187)
(%i188)
(%o188)
(%i189)
(%o189)
(%i190)
(%i191)
(%i192)
(%i193)
(%o193)
(%i194)
(%o194)
(%i195)
(%o195)
(%i196)
(%i197)
(%i198)
(%o198)
(%i199)
(%o199)
(%i200)
(%o200)
(%i201)
(%i202)
(%o202)
(%i203)
(%o203)
(%i204)
(%i205)
(%i206)
(%i207)
(%i208)
(%i209)
(%i210)
(%i211)
(%i212)
(%o212)
(%i213)
(%o213)
" -------------------------------------------------"
" This differs by a sign compared to Schwinger. "
" -----------------------------------------------"
"CASE: e(-,p1,+1) e(+,p2,-1) --> gamma(k1,-1) gamma(k2,+1) "
" -------------------------------------------------"
" spinors and denominators are the same , recompute g1 and g2"
comp_def(e1_cc(0,1/sqrt(2),%i/sqrt(2),0),
e2_cc(0,1/sqrt(2),%i/sqrt(2),0))
listarray(e1_cc)
[0,1/sqrt(2),%i/sqrt(2),0]
listarray(e2_cc)
[0,1/sqrt(2),%i/sqrt(2),0]
74
(%i214)
(%o214)
(%i215)
(%o215)
(%i216)
(%i217)
(%o217)
(%i218)
(%o218)
(%i219)
(%o219)
(%i220)
(%o220)
(%i221)
(%o221)
(%i222)
(%o222)
(%i223)
(%i224)
(%o224)
(%i225)
(%o225)
(%i226)
(%i227)
(%i228)
(%i229)
(%i230)
(%i231)
(%i232)
(%i233)
(%o233)
(%i234)
(%o234)
(%i235)
(%o235)
(%i236)
(%o236)
(%i237)
(%i238)
(%o238)
" -------------------------------------------------"
" This differs by a sign compared to Schwinger. "
" -------------------------------------------------"
"CASE: e(-,p1,+1) e(+,p2,-1) --> gamma(k1,+1) gamma(k2,+1) "
" -------------------------------------------------"
comp_def(e1_cc(0,(-1)/sqrt(2),%i/sqrt(2),0),
e2_cc(0,1/sqrt(2),%i/sqrt(2),0))
listarray(e1_cc)
[0,-1/sqrt(2),%i/sqrt(2),0]
listarray(e2_cc)
[0,1/sqrt(2),%i/sqrt(2),0]
g1:sL(e2_cc) . (m*I4-sL(k1)+sL(p1)) . sL(e1_cc)
matrix([2*m,0,-2*(M/2-cos(th)*v*M/2),0],[0,0,0,0],
[-2*(cos(th)*v*M/2-M/2),0,2*m,0],[0,0,0,0])
g2:sL(e1_cc) . (m*I4-sL(k2)+sL(p1)) . sL(e2_cc)
matrix([0,0,0,0],[0,2*m,0,-2*(cos(th)*v*M/2+M/2)],[0,0,0,0],
[0,-2*(-cos(th)*v*M/2-M/2),0,2*m])
" M1 = Mtn/Mtd "
Mtn:vp2b . g1 . up1
cos((%pi-th)/2)*sqrt(-(v-1)*M/2)
*(2*m*cos(th/2)*sqrt((v+1)*M/2)
-2*cos(th/2)*sqrt(-(v-1)*M/2)*(cos(th)*v*M/2-M/2))
-cos((%pi-th)/2)*sqrt((v+1)*M/2)
*(2*m*cos(th/2)*sqrt(-(v-1)*M/2)
-2*cos(th/2)*sqrt((v+1)*M/2)*(M/2-cos(th)*v*M/2))
75
(%i239)
(%o239)
(%i240)
(%o240)
(%i241)
(%o241)
(%i242)
(%o242)
(%i243)
(%o243)
(%i244)
(%o244)
(%i245)
(%o245)
(%i246)
(%o246)
(%i247)
(%o247)
(%i248)
(%o248)
(%i249)
expand(ratsubst(sin(th/2),cos((%pi-th)/2),%))
cos(th/2)*sin(th/2)*M2-cos(th/2)*sin(th/2)*cos(th)*v*M2
expand(ratsubst(sin(th)/2,cos(th/2)*sin(th/2),%))
sin(th)*M2/2-cos(th)*sin(th)*v*M2/2
Mtn:pullfac(%,sin(th)*M2/2)
sin(th)*(1-cos(th)*v)*M2/2
M1:Mtn/Mtd
-sin(th)
Mun:vp2b . g2 . up1
sin((%pi-th)/2)*sqrt((v+1)*M/2)
*(2*m*sin(th/2)*sqrt(-(v-1)*M/2)
-2*sin(th/2)*sqrt((v+1)*M/2)*(cos(th)*v*M/2+M/2))
-sin((%pi-th)/2)*sqrt(-(v-1)*M/2)
*(2*m*sin(th/2)*sqrt((v+1)*M/2)
-2*sin(th/2)*sqrt(-(v-1)*M/2)*(-cos(th)*v*M/2-M/2))
expand(ratsubst(cos(th/2),sin((%pi-th)/2),%))
-cos(th/2)*sin(th/2)*cos(th)*v*M2-cos(th/2)*sin(th/2)*M2
expand(ratsubst(sin(th)/2,cos(th/2)*sin(th/2),%))
-cos(th)*sin(th)*v*M2/2-sin(th)*M2/2
Mun:factor(%)
-sin(th)*(cos(th)*v+1)*M2/2
M2:Mun/Mud
sin(th)
Mfi:M2+M1
0
(display2d:true,
disp("CASE: e(-,p1,+1) e(+,p2,-1) --> gamma(k1,+1) gamma(k2,+1) "),
display(Mfi),display2d:false)
CASE: e(-,p1,+1) e(+,p2,-1) --> gamma(k1,+1) gamma(k2,+1)
Mfi = 0
12.16
moller3.mac: Squared Polarized Amplitudes Using Symbolic or Explicit Matrix Trace Methods
We provide here examples of using trace methods for the square of a polarized amplitude in the case of arbitrary energy
(finite mass) Moller scattering. This detailed verification using both explicit matrix traces and the symbolic traces takes
several minutes to carry out for each case, with the symbolic nc_tr method (equivalent to noncov (tr(..))) requiring about twice the computation time as the explicit matrix method m_tr.
The new feature is the tr or m_tr argument S(sv, Sp), in which either sv = 1 or sv = -1, and Sp is a symbol
for the particle spin 4-vector associated with the particles 4-momentum.
In the explicit matrix method, such an argument inserts a matrix factor P(sv,Sp), which turns into the matrix
(I4 + sv*Gam[5].sL(Sp))/2. This is the matrix version of the finite mass spin projection operator, and requires
a frame dependent definition (using comp_def) of the components of the spin 4-vector corresponding to a particles
4-momentum. ( See our section on high energy physics notation.)
When used with the symbolic tr method, the result is a factor 12 (1 + 5 /s), with = 1 being the value of sv and
/s being (Sp) .
76
Here is the batch file moller3.mac:
/* file moller3.mac
m_tr and nc_tr comparisons of
the square of polarized amplitudes
compared with dirac spinor results
found in moller2.mac
*/
" moller3.mac "$
"*********************************************"$
print ("
ver: ",_binfo%," date: ",mydate )$
" Maxima by Example, Ch. 12 "$
" Dirac Algebra and Quantum Electrodynamics "$
" Edwin L. Woollett "$
" http://www.csulb.edu/woollett "$
" [email protected] "$
"SQUARED POLARIZED AMPLITUDES VIA SYMBOLIC AND MATRIX TRACE METHODS"$
" FOR ARBITRARY ENERGY MOLLER SCATTERING "$
" e(-,p1,sv1) + e(-,p2,sv2) --> e(-,p3,sv3) + e(-,p4,sv4) "$
" --------------------------------------------------------"$
invar (D(p1,p1) = m2,
D(p2,p2) = m2,
D(p3,p3) = m2,
D(p4,p4) = m2,
D(p1,Sp1) = 0,
D(Sp1,Sp1) = -1,
D(p2,Sp2) = 0,
D(Sp2,Sp2) = -1,
D(p3,Sp3) = 0,
D(Sp3,Sp3) = -1,
D(p4,Sp4) = 0,
D(Sp4,Sp4) = -1 )$
77
s_th : VP (p1+p2,p1+p2);
t_th : VP (p1-p3,p1-p3);
u_th : VP (p1-p4,p1-p4);
78
if M1n_diff # 0 then (
disp ("M1n symbolic
return (M1n_diff)),
if M2n_diff # 0 then (
disp ("M2n symbolic
return (M2n_diff)),
79
if M12n_diff # 0 then (
disp ("M21n symbolic
return (M21n_diff)),
if M21n_diff # 0 then (
disp ("M21n symbolic
return (M21n_diff)),
display ([sv1,sv2,sv3,sv4]))$
and here are some cases worked out. After loading dirac2.mac and batching moller3.mac (which loads also
MSQcomp.mac), interactive work begins with input (%i28) below:
(%i35) load(dirac2);
(%o1) "c:/work5/dirac2.mac"
(%i2) batch ("moller3.mac");
read and interpret file: #pc:/work5/moller3.mac
(%i3) " moller3.mac "
(%i4) "*********************************************"
80
(%i5) print("
ver: ",_binfo%," date: ",mydate)
ver: Maxima 5.23.2
date: 2011-04-13
(%i6) " Maxima by Example, Ch. 12 "
(%i7) " Dirac Algebra and Quantum Electrodynamics "
(%i8) " Edwin L. Woollett "
(%i9) " http://www.csulb.edu/woollett "
(%i10) " [email protected] "
(%i11) " SQUARED POLARIZED AMPLITUDES VIA SYMBOLIC AND MATRIX TRACE METHODS"
(%i12) " FOR ARBITRARY ENERGY MOLLER SCATTERING "
(%i13) " e(-,p1,sv1) + e(-,p2,sv2) --> e(-,p3,sv3) + e(-,p4,sv4) "
(%i14) " --------------------------------------------------------"
(%i15) invar(D(p1,p1) = m2,D(p2,p2) = m2,D(p3,p3) = m2,D(p4,p4) = m2,
D(p1,Sp1) = 0,D(Sp1,Sp1) = -1,D(p2,Sp2) = 0,D(Sp2,Sp2) = -1,
D(p3,Sp3) = 0,D(Sp3,Sp3) = -1,D(p4,Sp4) = 0,D(Sp4,Sp4) = -1)
(%i16) comp_def(p1(E,0,0,p),Sp1(p/m,0,0,E/m),p2(E,0,0,-p),Sp2(p/m,0,0,(-E)/m),
p3(E,p*sin(th),0,p*cos(th)),
Sp3(p/m,E*sin(th)/m,0,E*cos(th)/m),
p4(E,-p*sin(th),0,-p*cos(th)),
Sp4(p/m,(-E*sin(th))/m,0,(-E*cos(th))/m))
(%i17) p_Em(expr):=expand(ratsubst(E2-m2,p2,expr))
(%i18) E_pm(expr):=expand(ratsubst(m2+p2,E2,expr))
(%i19) s_th:VP(p2+p1,p2+p1)
(%o19) 4*E2
(%i20) t_th:VP(p1-p3,p1-p3)
(%o20) 2*p2*cos(th)-2*p2
(%i21) u_th:VP(p1-p4,p1-p4)
(%o21) -2*p2*cos(th)-2*p2
(%i22) t_th2:to_ao2(t_th,th)
(%o22) -4*p2*sin(th/2)2
(%i23) u_th2:to_ao2(u_th,th)
(%o23) 4*p2*sin(th/2)2-4*p2
(%i24) t_thE:p_Em(t_th)
(%o24) 2*cos(th)*E2-2*E2-2*m2*cos(th)+2*m2
(%i25) u_thE:p_Em(u_th)
(%o25) -2*cos(th)*E2-2*E2+2*m2*cos(th)+2*m2
(%i26) load("MSQcomp.mac")
" MSQcomp() to compare matrix trace, symbolic trace
methods for square of polarized amplitudes
with square of spinor amplitudes. This is an
automated comparison, assuming A_spinor is
globally defined and also global sv1,sv2,sv3,sv4.
To see progress details, set details to true."
(%o27) "moller3.mac"
(%i28) /* case RR --> LL */
[sv1,sv2,sv3,sv4]:[1,1,-1,-1]$
(%i29) A_spinor : 2*m2/p2$
(%i30) MSQcomp();
" each case comparison could take 2 plus minutes "
" agreement "
[sv1,sv2,sv3,sv4] = [1,1,-1,-1]
(%o30) done
(%i31) time(%);
(%o31) [115.91]
(%i32) /* case RR --> RL */
[sv1,sv2,sv3,sv4]:[1,1,1,-1]$
(%i33) A_spinor : m*sin(th/2)*E/(p2*cos(th/2))-m*cos(th/2)*E/(p2*sin(th/2))$
(%i34) MSQcomp();
" each case comparison could take 2 plus minutes "
" agreement "
[sv1,sv2,sv3,sv4] = [1,1,1,-1]
(%o34) done
81
(%i35) time(%);
(%o35) [120.71]
(%i36) /* case RR --> RR */
[sv1,sv2,sv3,sv4]:[1,1,1,1]$
(%i37) A_spinor : m2*sin(th/2)2/(p2*cos(th/2)2)+2*sin(th/2)2/cos(th/2)2
+m2*cos(th/2)2/(p2*sin(th/2)2)
+2*cos(th/2)2/sin(th/2)2+4$
(%i38) MSQcomp();
" each case comparison could take 2 plus minutes "
" agreement "
[sv1,sv2,sv3,sv4] = [1,1,1,1]
(%o38) done
(%i39) time(%);
(%o39) [122.34]
(%i40) /* case RL --> RL */
[sv1,sv2,sv3,sv4]:[1,-1,1,-1]$
(%i41) A_spinor : m2*cos(th/2)2/(p2*sin(th/2)2)+
2*cos(th/2)2/sin(th/2)2-m2/p2$
(%i42) MSQcomp();
" each case comparison could take 2 plus minutes "
" agreement "
[sv1,sv2,sv3,sv4] = [1,-1,1,-1]
(%o42) done
(%i43) time(%);
(%o43) [122.5]
(%i44) /* case RL --> LR */
[sv1,sv2,sv3,sv4]:[1,-1,-1,1]$
(%i45) A_spinor : m2*sin(th/2)2/(p2*cos(th/2)2)+
2*sin(th/2)2/cos(th/2)2-m2/p2$
(%i46) MSQcomp();
" each case comparison could take 2 plus minutes "
" agreement "
[sv1,sv2,sv3,sv4] = [1,-1,-1,1]
(%o46) done
(%i47) time(%);
(%o47) [123.52]
12.17
82
bhabha2.mac: Arbitrary energy electron-positron scattering.
compton0.mac: Photon plus scalar charged particle scattering.
compton1.mac: Photon plus Lepton scattering.
moller0.mac: Scalar plus scalar charged particle scattering.
moller1.mac: High energy limit of electron plus electron scattering.
moller2.mac: Arbitrary energy electron plus electron scattering.
moller3.mac: Use of explicit matrix trace methods and symbolic trace methods for the squared polarized amplitudes for arbitrary energy electron plus electron scattering.
pair1.mac: Unpolarized two photon annihilation of an electron-positron pair.
pair2.mac: Polarized two photon annihilation of an electron-positron pair.
photon1.mac: Sum identities for photon polarization 3-vectors.
In addition to the above files, there is the file MSQcomp.mac which defines a function used by (and loaded by)
moller3.mac.
12.18
There are sixteen test suite files, and once dirac2.mac has been loaded, there are convenient abbreviations available to
run each of these sixteen test files separately.
dgintro2-test.mac: run using tin(),
dgtrace2-test.mac: run using tt1(),
dgtrace2_test.mac: run using tt2(),
dgcon2-test.mac: run using tcon(),
dgmcon-test.mac: run using tmcon(),
dgeval2-test.mac: run using teval(),
bhabha1-test.mac: run using tb1(),
bhabha2-test.mac: run using tb2(),
compton0-test.mac: run using tc0(),
compton1-test.mac: run using tc1(),
moller0-test.mac: run using tm0(),
moller1-test.mac: run using tm1(),
moller2-test.mac: run using tm2(),
moller3-test.mac: run using tm3(),
pair1-test.mac: run using tp1(),
pair2-test.mac: run using tp2()
83
When you make your own modifications to the Dirac package (perhaps to fit your own research goals), you can assure
yourself that your new code has not broken anything significant by running these sixteen test files. Once you have loaded
dirac2.mac, you can continue to use the above abbreviations to run one test file at a time, and you do not need to
manually reload dirac2.mac.
To run a test file manually (without using the abbreviations defined in dirac2.mac), you would need two lines for each
test file. Here is an example:
load ("dirac2.mac");
batch ("dgintro2-test.mac", test );
12.19
Using simplifying-new.lisp