Mathematical Algorithms using Matlab, Maple, and C Anton Betten March 12, 2008

advertisement
Mathematical Algorithms using Matlab, Maple, and C
Anton Betten1
March 12, 2008
1
with contributions from Victor Ginting, James Liu, Simon Tavener
2
Contents
1 Matlab
1.1 Lecture
1.2 Lecture
1.3 Lecture
1.4 Lecture
1.5 Lecture
1.6 Lecture
1.7 Lecture
1.8 Lecture
1.9 Lecture
1.10 Lecture
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5
5
10
14
19
21
27
32
32
34
36
2 Maple
2.1 Lecture 1: Introduction . . . . . . . . . . . .
2.2 Lecture 2: Plotting . . . . . . . . . . . . . . .
2.3 Lecture 3 and 4: Exploring Matrices . . . . .
2.4 Lecture 5: Sierpinski Triangles . . . . . . . .
2.5 Lecture 6: Basic Cryptography . . . . . . . .
2.6 Lecture 7: Mortgage Calculations . . . . . . .
2.7 Lecture 8: Magic Squares and Recursion . . .
2.8 Lecture 9: Partitions . . . . . . . . . . . . . .
2.9 Lecture 10: The Traveling Salesman Problem
2.10 Lecture 11: Mandelbrot Sets . . . . . . . . .
2.11 Lecture 12: Elliptic Curves . . . . . . . . . .
2.12 Lecture 13: A Sudoku Puzzle Solver . . . . .
2.13 Lecture 14: The Complex Function 1 over z .
2.14 Lecture 15: Calculus . . . . . . . . . . . . . .
2.15 Calculus Lab 1 . . . . . . . . . . . . . . . . .
2.16 Calculus Lab 2 . . . . . . . . . . . . . . . . .
2.17 Calculus Lab 3 . . . . . . . . . . . . . . . . .
2.18 Calculus Lab 4 . . . . . . . . . . . . . . . . .
2.19 Calculus Lab 5 . . . . . . . . . . . . . . . . .
2.20 Calculus Lab 6 . . . . . . . . . . . . . . . . .
2.21 Calculus Lab 7 . . . . . . . . . . . . . . . . .
2.22 Calculus Lab 8 . . . . . . . . . . . . . . . . .
2.23 Calculus Lab 9 . . . . . . . . . . . . . . . . .
2.24 Calculus Lab 10 . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
39
39
48
72
80
88
92
98
107
111
130
133
148
152
153
153
157
166
168
171
174
175
177
179
181
1
2
3
4
5
6
7
8
9
10
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3 C-Programming
3.1 Hello World . . . . . . . . . . . . . . . . . . . .
3.2 Fibonacci Numbers . . . . . . . . . . . . . . . .
3.3 A Simple Encryption Scheme . . . . . . . . . .
3.4 Roots of a Quadratic Polynomial . . . . . . . .
3.5 Two-Dimensional Geometry . . . . . . . . . . .
3.6 Home-Grown Square Roots . . . . . . . . . . .
3.7 Horner’s Algorithm for Polynomials . . . . . .
3.8 Lily Numbers . . . . . . . . . . . . . . . . . . .
3.9 Two by Two Matrices . . . . . . . . . . . . . .
3.10 Perfect Numbers . . . . . . . . . . . . . . . . .
3.11 Computing Pi . . . . . . . . . . . . . . . . . . .
3.12 Computing Primes: the Naive Way . . . . . . .
3.13 Computing Primes: the Sieve of Erathosthenes
3.14 Matrix Multiplication over a Finite Field . . .
3.15 Quicksort . . . . . . . . . . . . . . . . . . . . .
3.16 Computing the GCD of Two Integers . . . . . .
3.17 All k-Subsets of an n-Set . . . . . . . . . . . .
3.18 All k-Subsets of an n-Set, 2nd Method . . . . .
3.19 Repeated Squaring and Multiplying . . . . . .
3.20 The Travelling Salesmen Problem . . . . . . . .
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
183
183
183
184
185
186
188
189
191
191
193
193
194
195
196
198
201
202
203
205
206
Chapter 1
Matlab
1.1
Lecture 1
A few things in the beginning. Once you open the MATLAB workspace, many windows appear. One of
them is the workspace window, which is where you may type in commands for MATLAB. The other windows
are “Command History” which lists a history of commands that you typed, and “Workspace” which shows
all variables that you have defined in your current MATLAB session.
It is important to understand that MATLAB has the notion of a current directory. The current directory is
where MATLAB looks for files. More specifically, it looks for files with ending “.m” which are by convention
files containing MATLAB commands. You may create .m-files using an external text editor, for instance, and
you call the file by name from the MATLAB command window to have MATLAB read the file and execute
all commands in it. So, for instance if you have a file calles test.m then issuing “test” in the MATLAB
command window will have all commands in the file test.m be executed immediately. This way it is easy to
write “scripts”. A script is simply an .m-file containing commands in it.
Here are a few simple commands:
x = [1 2 3 4 5]
creates a (row-) vector x with the five entries 1,2,3,4,5. Note that MATLAB does not use commas but spaces
to separate the entries. Also note that you would have to type the command after the MATLAB command
prompt >>, so that you really would see something like this:
>>x = [1 2 3 4 5]
MATLAB anwers
x =
1
2
3
4
5
This means that MATLAB has allocated the variable x in its workspace and that x is the row vector
(1, 2, 3, 4, 5). In order to create a column vector, we write
u = [1;2;3;4;5]
And MATLAB replies
u =
5
1
2
3
4
5
which is clearly a column vector. We could define a second vector
y = [10 9 8 7 6]
and then add the two row-vectors x and y like this:
z = x + y
(the spaces are redundant, their sole purpose is to enhance readability). MATLAB replies
z =
11
11
11
11
11
It is very easy to apply a function to all elements of a vector. For instance
x.^2
squares each entry of x so that we obtain
ans =
1
4
9
16
25
By default, MATLAB stores the result of a computation in ans. The sum command can be used to sum up
all entries of a vector. For instance
sum(x.^2)
yields 55 (= 1 + 4 + 9 + 16 + 25). We can form logical expressions. The convention here is that 1 stands for
’true’ and 0 stands for ’false’. For instance
3 < 5
yields
ans =
1
whereas
3 > 5
yields
ans =
0
We could count the number of entries that are greater than 5 (for instance) like this:
sum(x.^2 >= 5)
6
The answer is
ans =
3
This is because for three entries, x2 > 5 evaluates to true (= 1), namely 32 > 5, 42 > 5 and 52 > 5 are all
true, and hence add one to the sum. The other cases yield 12 > 5 and 22 > 5 which are false, i.e. 0, and
hence do not contribute to the sum. The zeros command can be used to make zero matrices. For instance,
we have
>> z = zeros(5,1)
z =
0
0
0
0
0
>> z = zeros(1,5)
z =
0
0
0
0
0
Next, we could set up a little loop to fill the 5 entries in the vector z with something reasonable. Assume
we wish to make z = (1, 2, 3, 4, 5). We could write
for i=1:5
z(i) = i
end
The colon notation 1 : 5 stands for the integers 1, 2, 3, 4, 5 in turn. z(i) is the ith entry of the vector z. The
for - end construct is defining a loop, i.e. i will take all values 1, 2, 3, 4, 5 in turn and z(i) will be assigned as
i. The output makes it more clear how a loop works. Matlab prints the vector z after each loop iteration.
We can see how the vector fills up one by one:
z =
1
0
0
0
0
1
2
0
0
0
1
2
3
0
0
z =
z =
z =
7
1
2
3
4
0
1
2
3
4
5
z =
There is another way of creating vectors. Often, we wish to create eqaully spaced point over an interval.
The command linspace(a,b,n) does that. Here, a and b are the left and right endpoints of the interval and
n is the number of points which should be created. So, the next command creates 11 equally spaced points
on the unit interval:
x = linspace(0,1,11)
It results in
x =
Columns 1 through 6
0
0.1000
0.2000
0.3000
0.4000
0.8000
0.9000
1.0000
0.5000
Columns 7 through 11
0.6000
0.7000
The linspace command comes in handy when it comes to plotting functions. Say, we wish to plot the sin
function over the interval [−π, π]. We could do this as follows:
x = linspace(-pi,pi,500)
plot(x,sin(x))
Notice the plot command. The first argument x is the vector of 500 equally spaced points, the second
argument is a vector which is created by computing the sin values of each of the entries in x. This last
command creates a plot that is displayed in a separate window.
8
Lab 1
Create a word document containing the Matlab commands you used and the answers you obtained (including plots) for the following questions.
Question One: calculator functions
Calculate the following
(i) 7.5 + 3.1
(ii) 6 × 1.234
(iii) 23
(iv) sin(π/2)
(v) eln(2)
Question Two: operations on arrays
The first 8 Fibonacci number are 1, 1, 2, 3, 5, 8, 13, 21. The first 8 triangular nnumbers are 1, 3, 6, 10,
15, 21, 28, 36. Construct two arrays called fibonacci and triangle whose elements are the first 8 elements of
these two sequences. Let Fi and Ti be the ith Fibonacci number and ith triangular number respectively.
Calculate the following
(i) Compute 8 × Fi for i = 1 . . . 8
(ii) Compute Fi + Ti for i = 1 . . . 8
(iii) Compute Fi × Ti for i = 1 . . . 8
(iv) Compute Fi /Ti for i = 1 . . . 8
(v) Compute 1 + Ti for i = 1 . . . 8
(vi) Compute sin(Fi ) for i = 1 . . . 8
(vii) Compute eTi for i = 1 . . . 8
(viii) Compute max{Fi3 , Ti2 } for i = 1 . . . 8
Question Three: plotting a sequence of points
Make the following plots
(i) i vs 8 × Fi for i = 1 . . . 8
(ii) i vs Fi 3 for i = 1 . . . 8
Question Four: plotting a function
Plot the following functions for −π ≤ x ≤ π and label your axes.
Hint: The command linspace(-pi,pi,200) constructs an array with 200 equally space points between −π
and π.
(i) sin(x)
(ii) x − x3 /6
(iii) x − x3 /6 + x5 /120 − x7 /5040
9
M-Files
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
% Solutions for M151, lab #1
%
% Question One
fprintf(´“n Question One “n´)
7.5+3.1
6*1.234
2ˆ3-3ˆ2
sin(pi/4)ˆ2 + cos(pi/4)ˆ2
exp(3*log(2))
pause
% Question Two
fprintf(´“n Question Two “n´)
fib = [1 1 2 3 5 8 13 21]
tri = [1 3 6 10 15 21 28 36]
8 * fib
fib + tri
fib .* tri
fib ./ tri
1 + tri
sin(fib)
exp(tri)
fib.ˆ3
tri.ˆ2
max(fib.ˆ3, tri.ˆ2)
pause
% Question Three
fprintf(´“n Question 3(a) “n´)
plot(8*fib)
title(´Question 3(a)´)
pause
fprintf(´“n Question 3(b) “n´)
plot(fib.ˆ2)
title(´Question 3(b)´)
pause
% Question Four
fprintf(´“n Question Four “n´)
x=linspace(-pi,pi,200);
plot(x,sin(x),´-g´, x,x-x.ˆ3/6,´-r´, x,x-x.ˆ3/6+x.ˆ5/120-x.ˆ7/5040,´-b´)
1.2
Lecture 2
Lab 2
Create a word document containing the Matlab commands you used and the answers you obtained (including plots) for the following questions.
Question One: harmonic sum
Let N = 10k and for k = 0, . . . 7, compute the harmonic sum
Sk =
N
X
1
n
n=1
by
(a) summing from smallest to largest,
10
(b) summing from largest to smallest.
Use the command format long to find all significant digits. Does it appear that the sum converges as
N → ∞?
Extra credit: Do you always get the same number when summing from smallest to largest and when summing
from largest to smallest? If not, why not? Which do you think is the more accurate?
Question Two: catastrophic cancellation
Subracting two equally large numbers can be dangerous in finite precision arithmetic. Let n = 10k and for
k = 0, . . . 10, compute
(a) Ak = (n + 1)3 − n3
(b) Bk = 3n2 + 3n + 1
(c) Ek = |(Ak − Bk )/Bk |
Plot the relative error Ek against k.
Question Three: darts
Copy the program darts.m from the class website:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
%
%
%
%
%
M151: Laboratory Two
Darts
Add your own comments explaining what this script file does.
Hint: Does 3.14 remind you of anything?
clear
close all
clc
rand(´seed´,.123456)
NumberInside = 0;
Estimate = zeros(500,1);
for k=1:500
x = -1+2*rand(100,1);
y = -1+2*rand(100,1);
NumberInside = NumberInside + sum(x.ˆ2 + y.ˆ2 ¡= 1);
Estimate(k) = (NumberInside/(k*100))*4;
end
plot(Estimate)
title(´Your title´);
xlabel(´Your xlabel´)
ylabel(´Your ylabel´)
What does this program do and why?
Question Four: bubble sort
A bubble sort ranks a sequence of numbers from smallest to largest by comparing adjacent pairs of numbers
(neighbors) and permuting them as necessary.
Consider a sequence of locations 1, 2, . . . , N and an initial sequence of numbers a1 , a2 , a3 , a4 , . . . , aN . Compare the numbers in locations 1 and 2, i.e., a1 and a2 . If a1 > a2 swap their order, if a1 < a2 leave their
order unchanged. Next compare the numbers in locations 2 and 3. (Note that if a1 < a2 this will be a2 and
a3 , if a1 > a2 this will be a1 and a3 .) If the number in location 2 is greater than the number in location 3,
11
swap their order, otherwise leave unchanged. Repeat up to the final pair, i.e. locations N − 1 and N . This
process will “sweep” the largest number to location N . (After how many comparisons?) Repeat as necessary
until the entire sequence is ranked from smallest to largest.
Write a bubble sort program in Matlab and use it to sort 10 random integers between 0 and 1000.
Hint: Use the rand and round commands to generate random integers.
M-Files
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
% Script File: Clouds
%
% 2-dimensional pictures of the uniform and normal distributions.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function [swap] = bubble(N,M)
%
% *** [swap] = function bubble(N,M) ***
%
% Bubble sort algorithm
%
% Input
% N = size of vector to be sorted
% M = number of vectors of size N to be sorted
%
Points = rand(1000,2);
subplot(1,2,1)
plot(Points(:,1),Points(:,2),´.´)
title(´Uniform distribution.´)
axis([0 1 0 1])
axis(´square´)
Points = randn(1000,2);
subplot(1,2,2)
plot(Points(:,1),Points(:,2),´.´)
title(´Normal distribution.´)
axis([-3 3 -3 3])
axis(´square´)
for k=1:M
count=0;
% Create a vector of size N containing random integers between 0 and 1000
a=round(1000*rand(1,N));
for i=1:N
for j=1:N-i
if a(j+1) ¡ a(j)
tmp = a(j);
a(j) = a(j+1);
a(j+1) = tmp;
count=count+1;
end
end
end
swap(k)=count;
end
%swap
12
30
31
32
fprintf(´Mean number of swaps = %20.14e “n´, mean(swap))
fprintf(´Standard deviation = %20.14e “n´, std(swap))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function [rel˙error]=catastrophic˙cancellation(ik)
%
% *** [rel˙error]=catastrophic˙cancellation(ik) ***
%
% Computes the relative error from catastrophic cancelation
%
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
function [su,sd]=geometric˙sum(r,ik)
%
% *** function geometric˙sum(r,ik) ***
%
% Compute the geometric sum with ratio r for N = 1 .. 10ˆ(ik) by summing both from smallest to largest
% and from largest to smallest
%
1
2
3
4
5
6
7
8
9
10
11
12
function [su,sd]=harmonic˙sum(ik)
%
% *** [su,sd]=function harmonic˙sum(ik) ***
%
% Compute the harmonic sum for N = 1 .. 10ˆ(ik) by summing both from smallest to largest
% and from largest to smallest
%
for k=1:ik+1
N = 10ˆ(k-1);
A(k) = (N+1)ˆ3 - Nˆ3;
B(k) = 3*Nˆ2 + 3*N + 1;
fprintf(´A(%2i)=%20.14e, B(%2i)=%20.14e “n´,k-1, A(k), k-1, B(k))
end
rel˙error = abs( (A-B)./B )
plot(rel˙error)
title(´Catastrophic cancellation´)
xlabel(´k´)
ylabel(´Relative error´)
for k=1:ik+1
N=10ˆ(k-1);
sum˙up = 1;
for i = 1:N
sum˙up = sum˙up + rˆi;
end
su(k) = sum˙up;
sum˙down = 1;
for i = N:-1:1
sum˙down = sum˙down + rˆi;
end
sd(k) = sum˙down;
fprintf(´N = %15i, su(k) = %20.14e, sd(k) = %20.14e “n´, N, su(k), sd(k))
end
for k=1:ik+1
N=10ˆ(k-1);
sum˙up = 0;
13
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
for i = 1:N
sum˙up = sum˙up + 1/i ;
end
su(k) = sum˙up;
sum˙down = 0;
for i = N:-1:1
sum˙down = sum˙down + 1/i ;
end
sd(k) = sum˙down;
fprintf(´N = %15i, su(k) = %20.14e, sd(k) = %20.14e “n´, N, su(k), sd(k))
end
function [su,sd]=harmonic˙sum˙chop(d,ik)
%
% *** [su,sd]=function harmonic˙sum(d,ik) ***
%
% Compute the harmonic sum for N = 1 .. 10ˆ(ik) by summing both from smallest to largest
% and from largest to smallest
%
digits(d)
for k=1:ik
N=10ˆ(k-1);
sum˙up = 0;
for i = 1:N
sum˙up = sum˙up + vpa(1/i) ;
end
su(k) = sum˙up;
sum˙down = 0;
for i = N:-1:1
sum˙down = sum˙down + vpa(1/i) ;
end
sd(k) = sum˙down;
N
su
sd
end
%
fprintf(´Sum up = %12i “n´, sum˙up)
fprintf(´Sum down = %12i “n´, sum˙down)
1.3
Lecture 3
Lab 3
Create a word document containing the Matlab commands you used and the answers you obtained (including
plots) for the following questions.
Question One: Secants and tangents
For the following functions, plot the secant lines through the points (x0 , f (x0 )) and (x0 + h, f (x0 + h)) for
h = 21 , 41 , 18 and the tangent line to the function at x0 .
(a) f (x) = sin(x) at x0 =
(b) f (x) = tan(x) at x0 =
π
4
π
4
14
(c) f (x) = x3 − 3x2 + x − 3 at x0 = 2
Question Two: minima
For the following functions and closed intervals, plot the function, its derivative and the tangent to the graph
at the minimum.
(a) f (x) = sin(x) for x ∈ [−π, 0]
(b) f (x) = x2 + 4x + 3 at x ∈ [−5, 5]
(c) f (x) = x3 − x for x ∈ [−2, 2]
Question Three: Bisection
The polynomial f (x) = x4 − 18x3 + 4x2 + 738x + 650 has two zeros on the interval [0, 50]. Find them both
to an accuracy of less than 10−6 using the method of bisection.
Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
% M151: Laboratory Three
%
Question One
% Question 1a
clear
figure(1)
hold off
x = linspace(0,pi/2,100);
y = sin(x);
a = pi/4;
b = sin(a);
for h = [1/2, 1/4, 1/8]
c = a + h;
d = sin(c);
s = (d-b)/(c-a);
t = linspace(-1,1,10);
yt = b+s*t;
plot([a c],[b d],´ob´, x,y,´-k´, a+t,yt,´-r´)
axis([0 pi/2 0 1.4])
title(´sin(x) at x=pi/4´)
xlabel(´x´)
ylabel(´y´)
set(gca,´XTick´,0:pi/8:pi/2)
set(gca,´XTickLabel´,–´0´,´pi/8´,´pi/4´,´3pi/2´,´pi/2´˝)
hold on
end
tangent˙slope = cos(pi/4);
tangent = b + tangent˙slope*t;
plot(a+t,tangent,´-g´)
% Question 1b
clear
figure(2)
hold off
x = linspace(0,pi/2,100);
y = tan(x);
a = pi/4;
b = tan(a);
for h=[1/2, 1/4, 1/8]
c = a+h;
d = tan(c);
15
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
s = (d-b)/(c-a);
t = linspace(-1,1,10);
yt = b + s*t;
plot([a c],[b d],´ob´, x,y,´-k´, a+t,yt,´-r´)
axis([0 pi/2 0 5])
title(´tan(x) at x=pi/4´)
xlabel(´x´)
ylabel(´y´)
set(gca,´XTick´,0:pi/8:pi/2)
set(gca,´XTickLabel´,–´0´,´pi/8´,´pi/4´,´3pi/2´,´pi/2´˝)
hold on
end
tangent˙slope = (sec(pi/4))ˆ2;
tangent = b + tangent˙slope*t;
plot(a+t,tangent,´-g´)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
% M151: Laboratory Three
%
Question One
% Question 1c
clear
figure(3)
hold off
x = linspace(1,3,100);
y = x.ˆ3 - 3*x.ˆ2 + x - 3;
a = 2;
b = aˆ3 - 3*aˆ2 + a - 3;
for h = [1/2, 1/4, 1/8]
c = a + h;
d = cˆ3 - 3*cˆ2 + c - 3;
s = (d-b)/(c-a);
t = linspace(-1,1,10);
yt = b + s*t;
plot([a c],[b d],´ob´, x,y,´-k´, a+t,yt,´-r´)
axis([1 3 -8 0])
title(´xˆ3-3xˆ2+x-3 at x=2´)
xlabel(´x´)
ylabel(´y´)
hold on
end
tangent˙slope = 3*2ˆ2 - 6*2 + 1;
tangent = b + tangent˙slope*t;
plot(a+t,tangent,´-g´)
% Question 1a
clear
figure(1)
hold off
x = linspace(0,pi/2,100);
y = sin(x);
a = pi/4;
b = sin(a);
for h = [1/2, 1/4, 1/8]
c = a + h;
d = sin(c);
s = (d-b)/(c-a);
t = linspace(-1,1,10);
yt = b+s*t;
plot([a c],[b d],´ob´, x,y,´-k´, a+t,yt,´-r´)
axis([0 pi/2 0 1.4])
title(´sin(x) at x=pi/4´)
xlabel(´x´)
ylabel(´y´)
set(gca,´XTick´,0:pi/8:pi/2)
16
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
set(gca,´XTickLabel´,–´0´,´pi/8´,´pi/4´,´3pi/2´,´pi/2´˝)
hold on
end
tangent˙slope = cos(pi/4);
tangent = b + tangent˙slope*t;
plot(a+t,tangent,´-g´)
1
2
3
4
% M151: Laboratory Three
%
Question One
% Question 1b
clear
figure(2)
hold off
x = linspace(0,pi/2,100);
y = tan(x);
a = pi/4;
b = tan(a);
for h=[1/2, 1/4, 1/8]
c = a+h;
d = tan(c);
s = (d-b)/(c-a);
t = linspace(-1,1,10);
yt = b + s*t;
plot([a c],[b d],´ob´, x,y,´-k´, a+t,yt,´-r´)
axis([0 pi/2 0 5])
title(´tan(x) at x=pi/4´)
xlabel(´x´)
ylabel(´y´)
set(gca,´XTick´,0:pi/8:pi/2)
set(gca,´XTickLabel´,–´0´,´pi/8´,´pi/4´,´3pi/2´,´pi/2´˝)
hold on
end
tangent˙slope = (sec(pi/4))ˆ2;
tangent = b + tangent˙slope*t;
plot(a+t,tangent,´-g´)
% Question 1c
clear
figure(3)
hold off
x = linspace(1,3,100);
y = x.ˆ3 - 3*x.ˆ2 + x - 3;
a = 2;
b = aˆ3 - 3*aˆ2 + a - 3;
for h = [1/2, 1/4, 1/8]
c = a + h;
d = cˆ3 - 3*cˆ2 + c - 3;
s = (d-b)/(c-a);
t = linspace(-1,1,10);
yt = b + s*t;
plot([a c],[b d],´ob´, x,y,´-k´, a+t,yt,´-r´)
axis([1 3 -8 0])
title(´xˆ3-3xˆ2+x-3 at x=2´)
xlabel(´x´)
ylabel(´y´)
hold on
end
tangent˙slope = 3*2ˆ2 - 6*2 + 1;
tangent = b + tangent˙slope*t;
plot(a+t,tangent,´-g´)
% Question 1a
17
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
clear
figure(1)
hold off
x = linspace(0,pi/2,100);
y = sin(x);
a = pi/4;
b = sin(a);
for h = [1/2, 1/4, 1/8]
c = a + h;
d = sin(c);
s = (d-b)/(c-a);
t = linspace(-1,1,10);
yt = b+s*t;
plot([a c],[b d],´ob´, x,y,´-k´, a+t,yt,´-r´)
axis([0 pi/2 0 1.4])
title(´sin(x) at x=pi/4´)
xlabel(´x´)
ylabel(´y´)
set(gca,´XTick´,0:pi/8:pi/2)
set(gca,´XTickLabel´,–´0´,´pi/8´,´pi/4´,´3pi/2´,´pi/2´˝)
hold on
end
tangent˙slope = cos(pi/4);
tangent = b + tangent˙slope*t;
plot(a+t,tangent,´-g´)
% Question 1b
clear
figure(2)
hold off
x = linspace(0,pi/2,100);
y = tan(x);
a = pi/4;
b = tan(a);
for h=[1/2, 1/4, 1/8]
c = a+h;
d = tan(c);
s = (d-b)/(c-a);
t = linspace(-1,1,10);
yt = b + s*t;
plot([a c],[b d],´ob´, x,y,´-k´, a+t,yt,´-r´)
axis([0 pi/2 0 5])
title(´tan(x) at x=pi/4´)
xlabel(´x´)
ylabel(´y´)
set(gca,´XTick´,0:pi/8:pi/2)
set(gca,´XTickLabel´,–´0´,´pi/8´,´pi/4´,´3pi/2´,´pi/2´˝)
hold on
end
tangent˙slope = (sec(pi/4))ˆ2;
tangent = b + tangent˙slope*t;
plot(a+t,tangent,´-g´)
% Question 1c
clear
figure(3)
hold off
x = linspace(1,3,100);
y = x.ˆ3 - 3*x.ˆ2 + x - 3;
a = 2;
b = aˆ3 - 3*aˆ2 + a - 3;
for h = [1/2, 1/4, 1/8]
c = a + h;
d = cˆ3 - 3*cˆ2 + c - 3;
18
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
s = (d-b)/(c-a);
t = linspace(-1,1,10);
yt = b + s*t;
plot([a c],[b d],´ob´, x,y,´-k´, a+t,yt,´-r´)
axis([1 3 -8 0])
title(´xˆ3-3xˆ2+x-3 at x=2´)
xlabel(´x´)
ylabel(´y´)
hold on
end
tangent˙slope = 3*2ˆ2 - 6*2 + 1;
tangent = b + tangent˙slope*t;
plot(a+t,tangent,´-g´)
1.4
Lecture 4
Lab 4
Create a word document containing the Matlab commands you used and the answers you obtained (including
plots) for the following questions.
Print out your M-file. It should contain your name, the question number and be fully commented.
Question One: Bubble sorting
(i) Construct a sequence of 100 random integers between 0 and 1000 and sort using your bubble sort
program. Calculate the number of times a pair of numbers is switched when sorting 100 numbers
(ii) Repeat 1000 times and plot a histogram of the number of times a pair of numbers is switched when
sorting 100 numbers
(iii) Calculate the mean and standard deviation of the number of times the order of a pair of numbers is
switched when sorting 100 numbers using your bubble sort algorithm.
Question Two: Compound interest
The value V of an initial investment P in a savings account paying an annual interest rate r is given by
r mt
V =P 1+
m
where m is the number of times the interest is compounded in a year, and t is the number of years. If the
interest is compounded continuously, the value is given by V = P ert .
Consider an investment of $5000 for 15 years at an annual interest rate of 7.5%.
(a) Show the difference in the value of the account when the interest is compounded annual, quarterly and
continuously by constructing a plot that shows the value of the investment as a function of time for
each compounding method.
(b) Plot the difference in the final amount compounding annually, biannually, quarterly, monthly, weekly
and daily.
19
Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
function [V]=CompoundInterest(P,r,m,t)
%
% *** function [V]=CompoundInterest(P,r,m,t) ***
%
% Input
% P is the principle
% r is the annual interest rate
% m is an array containing a number of different compounding rates
% t is the term of the investment in years
%
% Output
% V(j) is the value of the investment at time D(j)
figure(1)
hold off
clf
Dcont = linspace(0,15,200);
Vcont = P*exp(r*Dcont);
plot(Dcont,Vcont,´-c´,´LineWidth´,3)
title(´Net worth´)
xlabel(´Years´)
ylabel(´Amount´)
axis([0 15 4000 16000])
hold on
k = length(m);
n = m*t;
D(1) = 0;
V(1) = P;
for j = 1:k
for i = 1:n(j)
D(i+1) = i/m(j) ;
V(i+1) = P* (1 + r/m(j))ˆi ;
end
Vfinal(j) = V(i+1);
Delta(j) = P*exp(r*t)-Vfinal(j);
fprintf(´m = %4i, Vfinal = $%9.2f, Delta = $%7.2f “n´, m(j), Vfinal(j), Delta(j))
switch 1
case j==1
plot(D,V,´s-r´)
case j==2
plot(D,V,´o-b´)
case j==3
plot(D,V,´-g´)
case j==4
plot(D,V,´-m´)
otherwise
plot(D,V,´-k´)
end
end
figure(2)
hold off
clf
plot(m,Delta,´s´)
title(´Difference due to compounding frequency´)
xlabel(´Compounding rate´)
ylabel(´Difference in final worth´)
20
1.5
Lecture 5
Lab 5
Create a word document containing the Matlab commands you used and the answers you obtained (including plots) for the following questions.
Print out your M-file. It should contain your name, the question number and be fully commented.
Question One: Newton’s method
Write a Matlab program to find a root of a function using Newton’s method. You must write a Matlab
function of the following form,
[ir,r]=newton(func1,func2,x,tol,itemax)
where
• func1 is an inline function which evaluates the function
• func2 is an inline function which evaluates the derivative
• x is an initial guess
• tol is the desired tolerance
• itemax is the maximum number of Newton iterations permitted.
• ir is an integer indicating whether or not the Newton iteration converged
• r is the root to the required tolerance
Use your program to find the all roots of the following polynomials
f1 (x) = x4 − 18x3 + 4x2 + 738x + 650
f2 (x) = x3 − 2x + 2
f3 (x) = x3 − 4.3x2 + 5.83x − 2.541
Question Two: Convergence of Newton’s method
Let xstep(i) be the step take at the ith iteration of Newton’s method. Comment on the convergence of
Newton’s method in all cases by tabulating xstep(i)/xstep(i-1) and xstep(i)/xstep(i-1)2 for the all
roots found in Question One.
Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
M151: Lab #5
============
Question One
-----------Function
Iteration
Iteration
Iteration
Iteration
#1, initial
1, da =
2, da =
3, da =
4, da =
guess = -5
0.056424,
-0.001130,
-0.000000,
-0.000000,
a
a
a
a
=
=
=
=
-5.056424,
-5.055293,
-5.055293,
-5.055293,
fa
fa
fa
fa
Convergence data for Newton method (quadratic)
xstep(i)/xstep(i-1) xstep(i)/xstep(i-1)ˆ2
21
= -65.000000
=
1.356693
=
0.000550
=
0.000000
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
-2.00338e-002
4.05694e-004
1.63722e-007
-3.55060e-001
-3.58901e-001
-3.57013e-001
Solution using Newtons method, root =
Function
Iteration
Iteration
Iteration
Iteration
#1, initial guess = -1
1, da = -0.096726,
2, da =
0.000847,
3, da =
0.000000,
4, da =
0.000000,
a
a
a
a
=
=
=
=
-5.0552928
-0.903274,
-0.904121,
-0.904121,
-0.904121,
fa
fa
fa
fa
= -65.000000
=
0.578959
=
0.000041
=
0.000000
Convergence data for Newton method (quadratic)
xstep(i)/xstep(i-1) xstep(i)/xstep(i-1)ˆ2
-8.75379e-003
9.05007e-002
7.14493e-005
8.43836e-002
5.49738e-009
9.08694e-002
Solution using Newtons method, root =
Function
Iteration
Iteration
Iteration
Iteration
Iteration
#1, initial
1, da =
2, da =
3, da =
4, da =
5, da =
guess = 10
-0.738832,
-0.098061,
-0.002673,
-0.000002,
-0.000000,
a
a
a
a
a
=
=
=
=
=
-0.9041206
10.738832,
10.836892,
10.839565,
10.839567,
10.839567,
fa
fa
fa
fa
fa
=
=
=
=
=
430.000000
44.106562
1.139433
0.000882
0.000000
Convergence data for Newton method (quadratic)
xstep(i)/xstep(i-1) xstep(i)/xstep(i-1)ˆ2
1.32724e-001
-1.79640e-001
2.72566e-002
-2.77956e-001
7.75533e-004
-2.90158e-001
5.98909e-007
-2.88931e-001
Solution using Newtons method, root =
Function
Iteration
Iteration
Iteration
Iteration
#1, initial guess = 13
1, da = -0.128968,
2, da =
0.009075,
3, da =
0.000047,
4, da =
0.000000,
a
a
a
a
=
=
=
=
10.8395671
13.128968,
13.119893,
13.119846,
13.119846,
fa
fa
fa
fa
= -65.000000
=
5.329178
=
0.027092
=
0.000001
Convergence data for Newton method (quadratic)
xstep(i)/xstep(i-1) xstep(i)/xstep(i-1)ˆ2
-7.03691e-002
5.45631e-001
5.13598e-003
5.65925e-001
2.63295e-005
5.64879e-001
Solution using Newtons method, root =
13.1198463
Question Two
-----------Function
Iteration
Iteration
Iteration
Iteration
Iteration
#2, initial
1, da =
2, da =
3, da =
4, da =
5, da =
guess = -1.5
0.342105, a
-0.069278, a
-0.003526, a
-0.000009, a
-0.000000, a
=
=
=
=
=
-1.842105,
-1.772827,
-1.769301,
-1.769292,
-1.769292,
fa
fa
fa
fa
fa
Convergence data for Newton method (quadratic)
xstep(i)/xstep(i-1) xstep(i)/xstep(i-1)ˆ2
22
=
=
=
=
=
1.625000
-0.566701
-0.026191
-0.000066
-0.000000
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
-2.02506e-001
5.08908e-002
2.53522e-003
6.41892e-006
-5.91940e-001
-7.34584e-001
-7.19084e-001
-7.18140e-001
Solution using Newtons method, root =
-1.7692924
Question Three
-------------Function
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
Iteration
#3, initial
1, da =
2, da =
3, da =
4, da =
5, da =
6, da =
7, da =
8, da =
9, da =
10, da =
11, da =
12, da =
13, da =
14, da =
15, da =
16, da =
17, da =
guess = 1
-0.047826, a =
-0.025456, a =
-0.013187, a =
-0.006720, a =
-0.003394, a =
-0.001705, a =
-0.000855, a =
-0.000428, a =
-0.000214, a =
-0.000107, a =
-0.000054, a =
-0.000027, a =
-0.000013, a =
-0.000007, a =
-0.000003, a =
-0.000002, a =
-0.000001, a =
1.047826, fa =
1.073282, fa =
1.086469, fa =
1.093190, fa =
1.096583, fa =
1.098289, fa =
1.099144, fa =
1.099572, fa =
1.099786, fa =
1.099893, fa =
1.099946, fa =
1.099973, fa =
1.099987, fa =
1.099993, fa =
1.099997, fa =
1.099998, fa =
1.099999, fa =
-0.011000
-0.002864
-0.000733
-0.000186
-0.000047
-0.000012
-0.000003
-0.000001
-0.000000
-0.000000
-0.000000
-0.000000
-0.000000
-0.000000
-0.000000
-0.000000
-0.000000
Convergence data for Newton method (quadratic)
xstep(i)/xstep(i-1) xstep(i)/xstep(i-1)ˆ2
5.32258e-001
-1.11290e+001
5.18053e-001
-2.03511e+001
5.09610e-001
-3.86435e+001
5.04967e-001
-7.51388e+001
5.02527e-001
-1.48080e+002
5.01274e-001
-2.93937e+002
5.00640e-001
-5.85638e+002
5.00321e-001
-1.16903e+003
5.00161e-001
-2.33582e+003
5.00080e-001
-4.66939e+003
5.00040e-001
-9.33653e+003
5.00020e-001
-1.86708e+004
5.00008e-001
-3.73392e+004
5.00003e-001
-7.46764e+004
5.00006e-001
-1.49353e+005
4.99935e-001
-2.98660e+005
Solution using Newtons method, root =
Function
Iteration
Iteration
Iteration
Iteration
Iteration
#3, initial guess = 2
1, da = -0.128571,
2, da =
0.027068,
3, da =
0.001499,
4, da =
0.000005,
5, da =
0.000000,
a
a
a
a
a
=
=
=
=
=
1.0999992
2.128571,
2.101504,
2.100005,
2.100000,
2.100000,
fa
fa
fa
fa
fa
=
=
=
=
=
Convergence data for Newton method (quadratic)
xstep(i)/xstep(i-1) xstep(i)/xstep(i-1)ˆ2
-2.10526e-001
1.63743e+000
5.53892e-002
2.04632e+000
3.00298e-003
2.00298e+000
9.00492e-006
2.00010e+000
Solution using Newtons method, root =
2.1000000
23
-0.081000
0.030227
0.001508
0.000005
0.000000
153
154
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
% M151: Lab 5
% Function #1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
% M151: Lab 5
% Function #2
user˙func = inline(´x.ˆ4 - 18*x.ˆ3 + 4*x.ˆ2 + 738*x + 650´, ´x´);
user˙deriv = inline(´4*x.ˆ3 - 54*x.ˆ2 + 8*x + 738´,´x´);
x=linspace(-10,15,100);
y=feval(user˙func,x);
z=feval(user˙deriv,x);
plot(x,y,´-k´,x,z,´--g´,[-10 15],[0 0],´:r´)
title(´Lab. 5, Qu. 1a´)
xlabel(´x´)
ylabel(´f(x)´)
pause
fprintf(´“nFunction #1, initial guess = -5 “n´)
[ir,r] = newton(user˙func,user˙deriv,-5,1E-6,8);
newton˙output(ir,r)
fprintf(´“nFunction #1, initial guess = -1 “n´)
[ir,r] = newton(user˙func,user˙deriv,-1,1E-6,8);
newton˙output(ir,r)
fprintf(´“nFunction #1, initial guess = 10 “n´)
[ir,r] = newton(user˙func,user˙deriv,10,1E-6,8);
newton˙output(ir,r)
fprintf(´“nFunction #1, initial guess = 13 “n´)
[ir,r] = newton(user˙func,user˙deriv,13,1E-6,8);
newton˙output(ir,r)
user˙func = inline(´x.ˆ3 - 2*x + 2´, ´x´);
user˙deriv = inline(´3*x.ˆ2 - 2´,´x´);
x=linspace(-3,3,100);
y=feval(user˙func,x);
z=feval(user˙deriv,x);
plot(x,y,´-k´,x,z,´-g´,[-3 3],[0 0],´:r´)
title(´Lab. 5, Qu. 1b´)
xlabel(´x´)
ylabel(´f(x)´)
pause
fprintf(´“nFunction #2, initial guess = -1.5 “n´)
[ir,r] = newton(user˙func,user˙deriv,-1.5,1E-6,8);
newton˙output(ir,r)
24
27
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
% M151: Lab 5
% Function #3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
%
user˙func = inline(´x.ˆ3 - 4.3*x.ˆ2 + 5.83*x - 2.541´, ´x´);
user˙deriv = inline(´3*x.ˆ2 - 8.6*x + 5.83´,´x´);
x=linspace(0,2.5,100);
y=feval(user˙func,x);
z=feval(user˙deriv,x);
plot(x,y,´-k´,x,z,´--g´,[0 2.5],[0 0],´:r´)
title(´Lab. 5, Qu. 1c´)
xlabel(´x´)
ylabel(´f(x)´)
pause
fprintf(´“nFunction #3, initial guess = 1 “n´)
[ir,r] = newton(user˙func,user˙deriv,1,1E-6,25);
newton˙output(ir,r)
fprintf(´“nFunction #3, initial guess = 2 “n´)
[ir,r] = newton(user˙func,user˙deriv,2,1E-6,8);
newton˙output(ir,r)
*** function [ir,r] = newton(user˙func,user˙deriv,a,tol,itemax,iplot) ***
Author: SJT
Date: 1/19/2005
Input
user˙func = an inline function defined by the user
user˙deriv = an inline function (the derivative) defined by the user
a
= an estimate of the root
tol
= desired tolerance
itemax
= the maximum number of iterations allowed
iplot
= 1 for plotting
Output
ir = 0 if Newton´s method converges
= 1 if maximum number of iterations exceeded
= 2 if divide by zero
r = an estimate of the root to the desired tolerance
function [ir,r] = newton(user˙func,user˙deriv,a,tol,itemax,iplot)
% Check input arguments
if nargin ¡ 6, iplot = 0; end
if nargin ¡ 5, itemax = 8; end
if nargin ¡ 4, tol = 1E-6; end
% Set x1 and x2 to left-hand and right-hand ends of initial bracket
ir = 0;
da = 1;
cnt = 0;
while abs(da) ¿ tol — abs(fa) ¿ tol
25
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
cnt = cnt + 1;
fa = feval(user˙func, a);
df = feval(user˙deriv,a);
% Plot if desired
if iplot == 1
newton˙plot(user˙func,user˙deriv,a,fa/df)
end
if abs(df) ¿ 1E-13
da = fa/df;
else
fprintf(´ERROR: Divide by zero in function newton “n´)
ir = 2;
return
end
a = a - da;
fprintf(´Iteration %3i, da = %12.6f, a = %12.6f, fa = %12.6f “n´,...
cnt, da, a, fa )
% Store convergence data
xstep(cnt) = da;
% Check for maximum number of iterations
if cnt ¿= itemax
fprintf(´ERROR: Maximum number of iterations exceeded “n´)
ir = 1;
break
end
end
% Set best estimate of root
r = a;
fprintf(´“nConvergence data for Newton method (quadratic) “n´)
fprintf(´xstep(i)/xstep(i-1) xstep(i)/xstep(i-1)ˆ2 “n´)
for i = 1:cnt-1
xratio(i) = xstep(i+1)/xstep(i);
xratio2(i) = xstep(i+1)/xstep(i)ˆ2;
fprintf(´%16.5e %18.5e “n´, xratio(i), xratio2(i))
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
% Demo of Newton´s method
user˙func = inline(´x.ˆ3 - 2*x.ˆ2 - x + 2´,´x´);
user˙deriv = inline(´3*x.ˆ2 - 4*x - 1´, ´x´);
1
2
3
function newton˙output(ir,r)
figure(1)
hold off
clf
fprintf(´Solve using Newtons method “n´)
[ir,r] = newton(user˙func,user˙deriv,3,1E-6,8,1);
if ir == 0
fprintf(´Solution using Newtons method %15.7e “n´,r)
elseif ir == 1
fprintf(´Maximum number of interations for Newtons exceeded “n´)
fprintf(´Solution %15.7e “n´,r)
else
fprintf(´Error in Newtons method “n´)
end
if ir == 0
26
4
5
6
7
8
9
10
fprintf(´“n“nSolution using Newtons method, root = %15.7f “n“n´,r)
elseif ir == 1
fprintf(´“n“nMaximum number of interations for Newtons exceeded “n´)
fprintf(´Final Newton estimate = %15.7f “n“n´,r)
else
fprintf(´“n“nError in Newtons method “n“n´)
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function newton˙plot(user˙func, user˙deriv, a, da)
nplot = 100;
x1 = 1.8;
x2 = 3.2;
y1 = -2;
y2 = 12;
xx = linspace(x1,x2,nplot);
yy = feval(user˙func,xx);
fa = feval(user˙func,a);
m = feval(user˙deriv,a);
yt = fa + m*(xx-a*ones(1,nplot));
figure(1)
plot(xx,yy,´-b´,xx,yt,´-g´,[x1 x2],[0 0],´-k´,[a a-da],[fa 0],´or´)
axis([x1 x2 y1 y2])
title(´Newtons method´)
xlabel(´x´)
ylabel(´y´)
hold on
1.6
Lecture 6
Lab 6
Create a word document containing the Matlab commands you used and the answers you obtained (including
plots) for the following questions.
Print out your M-file. It should contain your name, the question number and be fully commented.
Question One: Secant method
Write a Matlab program to find a root of a function using the secant method. You must write a Matlab
function of the following form,
[ir,r]=secant(func1,x,y,tol,itemax)
where
• func1 is an inline function which evaluates the function
• x is an initial guess
• y is a second initial guess
• tol is the desired tolerance
• itemax is the maximum number of secant iterations permitted.
• ir is an integer indicating whether or not the secant iteration converged
• r is the root to the required tolerance
27
Use your program to find the all roots of the following polynomials
f1 (x) = x4 − 18x3 + 4x2 + 738x + 650
f2 (x) = x3 − 2x + 2
f3 (x) = x3 − 4.3x2 + 5.83x − 2.541
Question Two: Convergence of the secant method
Let xstep(i) be the step taken at the ith step of the secant method. Comment on the convergence of the
secant method in all cases by tabulating xstep(i)/xstep(i-1) and xstep(i)/xstep(i-1)2 for the all roots
found in Question One.
Solution
1
2
3
4
5
6
user˙func = inline(´xˆ4 - 18*xˆ3 + 4*xˆ2 + 738*x + 650´, ´x´);
user˙deriv = inline(´4*xˆ3 - 54*xˆ2 + 8*x + 738´,´x´);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
% M151: Lab 6
% Function #1
1
2
3
4
5
6
7
% M151: Lab 6
% Function #2
[r] = secant(user˙func,9,10,1E-6,8)
[r] = newton(user˙func,user˙deriv,9,1E-6,8)
user˙func = inline(´x.ˆ4 - 18*x.ˆ3 + 4*x.ˆ2 + 738*x + 650´, ´x´);
x=linspace(-10,15,100);
y=feval(user˙func,x);
plot(x,y,´-k´,[-10 15],[0 0],´:r´)
title(´Lab. 6, Qu. 1a´)
xlabel(´x´)
ylabel(´f(x)´)
pause
fprintf(´“nFunction #1, initial guess = -5,-4 “n´)
[ir,r] = secant(user˙func,-5,-4,1E-6,8);
secant˙output(ir,r)
fprintf(´“nFunction #1, initial guess = -1,0 “n´)
[ir,r] = secant(user˙func,-1,0,1E-6,8);
secant˙output(ir,r)
fprintf(´“nFunction #1, initial guess = 9, 10 “n´)
[ir,r] = secant(user˙func,10,1E-6,8);
secant˙output(ir,r)
fprintf(´“nFunction #1, initial guess = 13,14“n´)
[ir,r] = secant(user˙func,13,14,1E-6,8);
secant˙output(ir,r)
user˙func = inline(´x.ˆ3 - 2*x + 2´, ´x´);
x=linspace(-3,3,100);
y=feval(user˙func,x);
28
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
plot(x,y,´-k´,[-3 3],[0 0],´:r´)
title(´Lab. 6, Qu. 1b´)
xlabel(´x´)
ylabel(´f(x)´)
pause
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
% M151: Lab 6
% Function #3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
%
% *** function [ir,r] = secant(user˙func,a,b,tol,itemax,iplot) ***
%
% Author: SJT
% Date: 1/19/2005
%
% Input
% user˙func = an inline function defined by the user
% a
= one estimate of the root
% b
= a second estimate of the root
% tol
= desired tolerance
% itemax = the maximum number of iterations allowed
% iplot
= 1 for plotting
%
% Output
% ir = 0 if secant method converges
%
= 1 if maximum number of iterations exceeded
%
= 2 if divide by zero
% r = an estimate of the root
%
function [ir,r] = secant(user˙func,a,b,tol,itemax,iplot)
fprintf(´“nFunction #2, initial guess = -1.5, -1 “n´)
[ir,r] = secant(user˙func,-1.5,-1,1E-6,8);
secant˙output(ir,r)
user˙func = inline(´x.ˆ3 - 4.3*x.ˆ2 + 5.83*x - 2.541´, ´x´);
x=linspace(0,2.5,100);
y=feval(user˙func,x);
plot(x,y,´-k´,[0 2.5],[0 0],´:r´)
title(´Lab. 6, Qu. 1c´)
xlabel(´x´)
ylabel(´f(x)´)
pause
fprintf(´“nFunction #3, initial guess = 0,1 “n´)
[ir,r] = secant(user˙func,0,1,1E-6,25);
secant˙output(ir,r)
fprintf(´“nFunction #3, initial guess = 2, 3 “n´)
[ir,r] = secant(user˙func,2,3,1E-6,8);
secant˙output(ir,r)
29
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
% Check input arguments
if nargin ¡ 6, iplot = 0; end
if nargin ¡ 5, itemax = 8; end
if nargin ¡ 4, tol = 1E-6; end
% Ensure that the two estimates are different
if abs(a-b) ¡ tol
fprintf(´Error: Two estimates are the same “n´)
return
end
% Evaluate the function at a and b
fa = feval(user˙func,a);
fb = feval(user˙func,b);
% Ensure that the initial bracket spans a root (warning only)
if fa*fb ¿ 0
fprintf(´WARNING: Initial range does not necessarily span a root “n´)
end
ir = 0;
cnt = 0;
while abs(a-b) ¿ tol — abs(fa) ¿ tol
cnt = cnt + 1;
% Relabel a and b so that the (absolute) function value at a is the smaller
if abs(fa) ¿ abs(fb)
tmp = a;
a = b;
b = tmp;
tmp = fa;
fa = fb;
fb = tmp;
end
% Calculate slope of secant line
slope = (fb-fa)/(b-a);
% Plot if desired
if iplot == 1
secant˙plot(user˙func,a,b,fa/slope)
end
% Old a
-¿ New b
% New estimate -¿ a
b = a;
fb = fa;
if abs(slope) ¿ 1E-13
da = fa/slope;
else
fprintf(´ERROR: Divide by zero in function secant “n´)
ir = 2;
return
end
a = a - da;
fa = feval(user˙func, a);
fprintf(´Iteration %3i, a = %12.6f, fa = %12.6f, b = %12.6f, fb = %12.6f “n´,...
cnt, a, fa, b, fb)
% Store convergence data
xstep(cnt) = da;
% Check for maximum number of iterations
if cnt ¿= itemax
fprintf(´ERROR: Maximum number of iterations exceeded “n´)
ir = 1;
break
30
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
end
end
% Set best estimate of root
r = a;
fprintf(´Convergence data for secant method (superlinear) “n´)
fprintf(´xstep(i)/xstep(i-1) xstep(i)/xstep(i-1)ˆ2 “n´)
for i = 1:cnt-1
xratio(i) = xstep(i+1)/xstep(i);
xratio2(i) = xstep(i+1)/xstep(i)ˆ2;
fprintf(´%16.5e %18.5e “n´, xratio(i), xratio2(i))
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
% Demo of secant´s method
1
2
3
4
5
6
7
8
9
10
function secant˙output(ir,r)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function secant˙plot(user˙func,a,b,da)
user˙func = inline(´x.ˆ3 - 2*x.ˆ2 - x + 2´,´x´);
user˙deriv = inline(´3*x.ˆ2 - 4*x - 1´, ´x´);
figure(1)
hold off
clf
fprintf(´Solve using secant method “n´)
[ir,r] = secant(user˙func,1.5,2.25,1E-6,15,1);
if ir == 0
fprintf(´Solution using secant method %15.7e “n´,r)
elseif ir == 1
fprintf(´Maximum number of iterations for secant method exceeded “n´)
fprintf(´Solution %15.7e “n´,r)
else
fprintf(´Error in secant method “n´)
end
if ir == 0
fprintf(´“n“nSolution using secant method, root = %15.7f “n“n´,r)
elseif ir == 1
fprintf(´“n“nMaximum number of interations for secant method exceeded “n´)
fprintf(´Final secant method estimate = %15.7f “n“n´,r)
else
fprintf(´“n“nError in secant method “n“n´)
end
nplot = 100;
x1 = 1.5;
x2 = 3.0;
y1 = -2;
y2 = 5;
xx = linspace(x1,x2,nplot);
yy = feval(user˙func,xx);
fa = feval(user˙func,a);
fb = feval(user˙func,b);
m = (fb-fa)/(b-a);
yt = fa + m*(xx-a*ones(1,nplot));
figure(1)
plot(xx,yy,´-b´,xx,yt,´-g´,[x1 x2],[0 0],´-k´,[a b a-da],[fa fb 0],´or´)
axis([x1 x2 y1 y2])
title(´Secant method´)
31
21
22
23
24
25
xlabel(´x´)
ylabel(´y´)
hold on
pause
1.7
Lecture 7
Lab 7
A parachutist leaps from an aeroplane and plunges towards Earth. His/her velocity is determined by the
initial value problem
dv
= mg − kv p ;
v(0) = v0 ,
(1.1)
m
dt
where m is the mass of the parachutist, v is his/her velocity (directly downwards), g is the accelaration due
to gravity, k and p are constants.
Assume g=10ms−2 and the force due to air resistance on a 70kg parachutist falling at 1ms−1 is measured to
be 70 Newton, thus k = 1 (the units depend upon the value of p) and let v0 = 0.
Question One
Let p = 1.
(a) Write a Matlab subroutine to implement Euler’s method to solve the initial value problem and write
the solution to a file.
(b) Write a separate Matlab subroutine to read the solution from a file and plot the velocity as a function
of time.
(c) Write a third Matlab subroutine to read the solution from a file, calculate the terminal velocity and
estimate how long it takes for the parachutist to reach 95% of his/her terminal velocity?
Question Two
Repeat Question One for p = 2.
1.8
Lecture 8
Lab 8
Question One
A parachutist leaps from an aeroplane and plunges towards Earth. His/her velocity is determined by the
initial value problem
dv
m
= mg − kv;
v(0) = 0,
(1.2)
dt
where m is the mass of the parachutist, v is his/her velocity (directly downwards), g is the accelaration due
to gravity, and k is a constant.
The exact solution is
gm
−kt
v(t) =
1 − exp
k
m
32
Let the approximate solution of the initial value problem obtained by Euler’s method with step size h be
Vh (t). Show that for a fixed value of t > 0, (t = 100 say) the error Vh (t) − v(t) decreases linearly with step
size h.
Question Two: Matlab o.d.e. solvers
A safety bumper is placed at the end of a racetrack to stop out-of-control cars. The bumper is designed such
that the force that the bumper applies to the car is a function of the velocity v and the displacement x of
the front edge of the bumper according to the equation
F = Kv 3 (x + 1)3
where K = 30kg · s/m5 is a constant. A car with mass m of 1500kg hits the bumper at a speed of 90km/hr.
Using the Matlab function, ode45, determine and plot the velocity of the car as a function of its position
for 0 ≤ x ≤ 3m.
33
Let displacement x be a function of time t, i.e., x = x(t). From Newton’s law, F = ma, we have
m a(x(t)) = −K v(x(t))3 (x(t) + 1)3
dv(x(t)
= −K v(x(t))3 (x(t) + 1)3
⇒m
dt
dv dx
⇒m
= −K v(x(t))3 (x(t) + 1)3
dx dt
dv
−Kv 2 (x + 1)3
⇒
=
dx
m
1.9
Lecture 9
Lab 9
Create a word document containing the Matlab commands you used and the answers you obtained (including plots) for the following questions.
Print out your M-file. It should contain your name, the question number and be fully commented.
Question One: Trapezoidal Rule
Write a Matlab program to approximate the definite integral
Z b
f (x) dx
a
using the trapezoidal rule. Use your program to evaluate
Z 10
ln(x) dx
1
using N intervals where N = 2k for k = 1, . . . , 10. Show that the error in evaluating an integral using the
trapezoidal rule is proportional to h2 , where h is the length of each subinterval.
Question Two: Simpson’s rule
Write a Matlab program to approximate the definite integral
Z b
f (x) dx
a
using Simpson’s rule. Use your program to evaluate
Z 10
ln(x) dx
1
using N intervals where N = 2k for k = 1, . . . , 10. Show that the error in evaluating an integral using
Simpson’s rule is proportional to h4 , where h is the length of each subinterval.
Solution
1
2
3
4
function [simpint]=simpson(simpdata)
a=simpdata.left;
b=simpdata.right;
34
5
6
7
8
9
10
11
12
13
14
15
16
17
18
n=simpdata.intervals;
f=inline(simpdata.func,simpdata.var);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
% Driver for Simpsons rule
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function [trapint]=trapezium(trapdata)
1
% Driver for trapezium rule
x=linspace(a,b,2*n+1);
dx = (b-a)/(2*n);
fact = dx/3;
simpint = 0;
for i=1:n
simpint = simpint + fact*( feval(f,x(2*i-1)) + 4*feval(f,x(2*i)) + feval(f,x(2*i+1)) );
end
simpdata.left = a;
simpdata.right = b;
simpdata.func = ´log(x)´;
simpdata.var = ´x´;
exact˙integral = inline( ´(b*log(b)-a*log(a))-(b-a)´, ´a´, ´b´ );
exact = feval(exact˙integral, a, b);
fprintf(´Intervals Approximation
Error “n´)
for i=1:8
n = 2ˆi;
simpdata.intervals = n;
[value] = simpson(simpdata);
error(i) = value - exact;
fprintf(´%6i %18.6e %18.6e “n´, n, value, error(i))
end
fprintf(´“nConvergence analysis “n´)
fprintf(´
h
ratio
ratio2
ratio3
ratio4“n´)
for i = 1:8
h = (b-a)/2ˆi;
ratio = error(i)/h;
ratio2 = error(i)/hˆ2;
ratio3 = error(i)/hˆ3;
ratio4 = error(i)/hˆ4;
fprintf(´%18.6e %18.6e %18.6e %18.6e %18.6e “n´, h, ratio, ratio2, ratio3, ratio4)
end
a = trapdata.left;
b = trapdata.right;
n = trapdata.intervals;
f = inline(trapdata.func,trapdata.var);
x = linspace(a,b,n+1);
dx = (b-a)/n;
fact = dx/2;
trapint = 0;
for i=1:n
trapint = trapint + fact*( feval(f,x(i)) + feval(f,x(i+1)) );
end
35
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
trapdata.left = a;
trapdata.right = b;
trapdata.func = ´log(x)´;
trapdata.var = ´x´;
exact˙integral = inline( ´(b*log(b)-a*log(a))-(b-a)´, ´a´, ´b´ );
exact = feval(exact˙integral, a, b);
fprintf(´Intervals Approximation
Error “n´)
for i=1:8
n = 2ˆi;
trapdata.intervals = n;
[value] = trapezium(trapdata);
error(i) = value - exact;
fprintf(´%6i %18.6e %18.6e “n´, n, value, error(i))
end
fprintf(´“nConvergence analysis “n´)
fprintf(´
h
ratio
ratio2
ratio3
ratio4“n´)
for i = 1:8
h = (b-a)/2ˆi;
ratio = error(i)/h;
ratio2 = error(i)/hˆ2;
ratio3 = error(i)/hˆ3;
ratio4 = error(i)/hˆ4;
fprintf(´%18.6e %18.6e %18.6e %18.6e %18.6e “n´, h, ratio, ratio2, ratio3, ratio4)
end
1.10
Lecture 10
Lab 10
Create a word document containing the Matlab commands you used and the answers you obtained (including plots) for the following questions.
Print out your M-files. They should contain your name and be fully commented.
The midpoint integration rule partitions the interval [a, b] into N subintervals x0 , x1 , · · · , xN and approximates the area on each subinterval [xn−1 , xn ] using the function value the midpoint of the subinterval,
i.e.
Z b
N
X
xn−1 + xn
(xn − xn−1 )
f (x) dx ≈
f
2
a
n=1
Question One
Use your midpoint rule method program to approximate
Z
10
ln(x) dx ,
1
using N intervals where N = 2k for k = 1, . . . , 10. Determine the convergence rate for the midpoint rule, i.e.
determine k such that the error is proportional to hk , where h is the length of each subinterval.
36
Question Two
Use your midpoint rule program to approximate
Z
1
2
1
dx .
x−1
Explain your results.
Solution
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function [simpint]=simpson(simpdata)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
% Driver for Simpsons rule
1
2
3
4
5
6
% Driver for Simpsons rule
a=simpdata.left;
b=simpdata.right;
n=simpdata.intervals;
f=inline(simpdata.func,simpdata.var);
x=linspace(a,b,2*n+1);
dx = (b-a)/(2*n);
fact = dx/3;
simpint = 0;
for i=1:n
simpint = simpint + fact*( feval(f,x(2*i-1)) + 4*feval(f,x(2*i)) + feval(f,x(2*i+1)) );
end
simpdata.left = a;
simpdata.right = b;
simpdata.func = ´1/xˆ2´;
simpdata.var = ´x´;
exact˙integral = inline( ´1/a-1/b´, ´a´, ´b´ );
exact = feval(exact˙integral, a, b);
fprintf(´Intervals Approximation
Error “n´)
for i=1:12
n = 2ˆi;
simpdata.intervals = n;
[value] = simpson(simpdata);
error(i) = value - exact;
fprintf(´%6i %18.6e %18.6e “n´, n, value, error(i))
end
fprintf(´“nConvergence analysis “n´)
fprintf(´
h
ratio
ratio2
ratio3
ratio4“n´)
for i = 1:12
h = (b-a)/2ˆi;
ratio = error(i)/h;
ratio2 = error(i)/hˆ2;
ratio3 = error(i)/hˆ3;
ratio4 = error(i)/hˆ4;
fprintf(´%18.6e %18.6e %18.6e %18.6e %18.6e “n´, h, ratio, ratio2, ratio3, ratio4)
end
nhalf = 10;
simpdata.left = a;
simpdata.right = b;
37
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
simpdata.func = ´1/(x-1)´;
simpdata.var = ´x´;
exact˙integral = inline( ´log(b-1)-log(a-1)´, ´a´, ´b´ );
exact = feval(exact˙integral, a, b);
fprintf(´Intervals Approximation
Error “n´)
for i=1:nhalf
n = 2ˆi;
simpdata.intervals = n;
[value] = simpson(simpdata);
error(i) = value - exact;
fprintf(´%6i %18.6e %18.6e “n´, n, value, error(i))
end
fprintf(´“nConvergence analysis “n´)
fprintf(´
h
ratio
ratio2
ratio3
ratio4“n´)
for i = 1:nhalf
h = (b-a)/2ˆi;
ratio = error(i)/h;
ratio2 = error(i)/hˆ2;
ratio3 = error(i)/hˆ3;
ratio4 = error(i)/hˆ4;
fprintf(´%18.6e %18.6e %18.6e %18.6e %18.6e “n´, h, ratio, ratio2, ratio3, ratio4)
end
38
Chapter 2
Maple
2.1
Lecture 1: Introduction
Lecture 1
This is a comment line. If you read this, then you have successfully started your session, congratulations!!!
I recommend you use ctrl-3 to adjust the font size. Better? yeah!
> 1+1;
2
Hey, we can compute 1+1, great.
> %+1;
3
The percent sign stands for the latest result, so you don’t have to type it again, that’s nice
> %+1;
4
Note that = is test for equality, not assignment
> x = 3;
x=3
The := is used to assign something to something. In this case, we assign the value 3 to x.
> x := 3;
x := 3
Now x has the value 3;
> x;
3
Test for equality:
> x = 3;
3=3
How can we get rid of the assignment? We need to unassign it, here is how this is done:
> x := ’x’;
x := x
> x;
x
That’s right, now x is a symbol without a value.
> x := 4;
x := 4
39
There’s another way to get rid of all assigned variables, it is to do a complete memory clear:
> restart;
> x;
x
OK, now everything is fresh again. Let’s move on. We are going to do some fractions, yeah!
> 1/3;
1/3
> 0.333333;
0.333333
1/3 and 0.333333 are not the same thing, so get used to it! However, if you want to treat 1/3 as floating
point number, you can use evalf.
> evalf(1/3);
0.3333333333
You can have more digits if you like:
> evalf(1/3,20);
0.33333333333333333333
Maple treats mathematical quantities exact, i.e. the way mathematicians would treat them. For applications,
you may want to switch to floating points. As we have seen, you can do that. Another example is that of
factorials. n! (read n factorial) is defined as the product of all numbers from 1 to n. For example 5! = 5 *
4 * 3 * 2 * 1 = 120:
> 5!;
120
Let’s do 6!= 6*5*4*3*2*1 = 6 * 5! = 6 * 120 = 720
> 6!;
720
Now let’s do double factorials
> 6!!;
2051606757903623233769945396419147517556755769539223380305682530859997744167578435281591346134039460490126954202883834710136
Wow, what was that? That was 6!! = 720! = 720 * 719 * 718 * ... * 2 * 1, which of course is a very large
number. Notice that Maple gives you the exact answer, even though you might not have expected such a
large output. This is typical for Maple. Now if you like, you can turn that number into a floating point.
Here, the percent notation comes in handy.
> evalf(%);
2.601218944 × 101746
Let’s give it a name using the assignment operator. Notice that it is now already the next to last result, so
we use the double percent notation. No output this time because of the colon.
> a := %%:
> evalf(a);
2.601218944 × 101746
>
evalf(a,30);
2.60121894356579510020490322708 × 101746
This was a floating point number with 100 decimal digits precision. Do you know what Pi is?
> Pi;
π
Hmmm, maybe you were expecting 3.14... Here we go:
> evalf(Pi);
40
3.141592654
Want more digits? Here we go:
>
evalf(Pi,30);
3.14159265358979323846264338328
OK, I hope you see the difference between a symbolic system and a numeric system. Maple is symbolic,
Matlab is numeric, for example. Let’s move on. Uhh adding fractions, let Maple do it:
>
1/3+1/5;
8
15
That was correct! 1/3 + 1/5 = 5/15 + 3/15 = 8/15.
>
1/%;
15
8
Now we want powers, this is how we do it:
>
2^2;
4
More powers:
>
2^3;
8
>
2^4;
16
Want more? Why not have a little loop? Guess what, Maple starts counting from 1 (I repeat: one)
>
for i to 10 do 2^i; end;
2
4
8
16
32
64
128
256
512
1024
You can do whatever you want inside the loop. Lets say you want to compute 2ˆi - 1
>
for i to 10 do 2^i - 1; end;
1
3
7
15
31
63
127
255
511
1023
Now we want to start the loop from i=2. This is how we do it.
>
for i from 2 to 10 do 2^i; end;
41
4
8
16
32
64
128
256
512
1024
Notice that the output starts with 2ˆ2 = 4 rather that 2ˆ1 = 2. I want a sequence. Notice the assign
operator :=
> seq1 := 1,2,3;
seq1 := 1, 2, 3
Another one:
> seq2 := 4,5,6;
seq2 := 4, 5, 6
Let’s concatenate the sequences:
> seq3 := seq1,seq2;
seq3 := 1, 2, 3, 4, 5, 6
Let’s access elements of the sequence, for example the third:
> seq3[3];
3
Uhh, don’t access the zeroth element, this is Maple and not C, OK!?
> seq3[0];
\begin{Maple Error}{\normalsize{Error, invalid subscript selector}}\end{Maple Error}
Let’s make the sequence longer:
> seq3 := seq3,7,8,9;
seq3 := 1, 2, 3, 4, 5, 6, 7, 8, 9
How long is it?
> length(seq3);
19
Well, that can’t be right. In fact you must use nops and square brackets, don’t ask why at this point
> nops([seq3]);
9
OK let’s add more stuff:
> seq3 := seq3,x,y,z;
seq3 := 1, 2, 3, 4, 5, 6, 7, 8, 9, x, y, z
> nops([seq3]);
12
You have noticed that we always have a semicolon at the end of a command. We can also have a colon.
That would then suppress output, as follows:
> seq3:=seq3,d,e,f:
Want to see seq3 ?, here you go:
> seq3;
42
1, 2, 3, 4, 5, 6, 7, 8, 9, x, y, z, d, e, f
Lets make a sequence of the first few powers of 2:
> S := seq( 2^i, i=1..10);
S := 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024
We could also do it this way:
> S := seq( 2^i, i=1,2,3,4,5,6,7,8,9,10);
S := 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024
Let’s do something crazy
> S := seq(i^2, i=x,y,z);
S := x2 , y 2 , z 2
These are just symbolic terms, we cannot do much with them now. Notice that we have overwritten S each
time. In the last few examples. That is OK, as long as we don’t need the old content any more.
> %[2];
y2
BTW, that was the second element of S. Now we want to have a set:
> 1,2,3,4,5;
{1, 2, 3, 4, 5}
Let’s give it a name:
> S := %;
S := {1, 2, 3, 4, 5}
Another set:
> T := 2,4,6,8;
T := {2, 4, 6, 8}
union, minus, intersect:
> S union T;
{1, 2, 3, 4, 5, 6, 8}
> S minus T;
{1, 3, 5}
> S intersect T;
{2, 4}
Is 2 a member of S?
> member(2, S);
true
OK, and at which position?
> member(2, S, ’position’);
true
> position;
2
OK, second position of S.
> S[2];
2
> for i to 10 do
> 2^i;
> end;
43
2
4
8
16
32
64
128
256
512
1024
>
>
>
for i from 0 to 10 do
2^i;
end;
1
2
4
8
16
32
64
128
256
512
1024
>
>
>
for i from 0 to 10 do
printf("%d ", 2^i);
end;
\begin{Maple Normal}{\normalsize{1 2 4 8 16 32 64 128 256 512 1024 }}\end{Maple Normal}
>
A := Matrix(4,4);

>

0
0
0
0

 0

A := 
 0

0
0
0
0
0
0
0

0 


0 

0
A[1,1];
0
>
A[4,4];
0
>
A[5,5];
\begin{Maple Error}{\normalsize{Error, Matrix index out of range}}\end{Maple Error}
44
for i from 1 to 4 do
for j from 1 to 4 do
A[i,j] := 1/(i+j);
end;
end;
> A;
>

>

1/2
1/3
1/4
1/5

 1/3


 1/4

1/5
1/4
1/5
1/5
1/6
1/6
1/7

1/6 


1/7 

1/8
A[4,4];
1/8
with(LinearAlgebra):
Using the with-command allows us to load a package. In this case, we are loading the Linear Algebra package
since we want to do matrix inversion:
> Av := MatrixInverse(A);


200
−1200
2100
−1120


 −1200
8100
−15120
8400 


Av := 

 2100 −15120 29400 −16800 


>
−1120
8400
−16800
9800
Let’s test if this really is the inverse of A. We simply multiply A by Av. Note that we cannot use the usual
* operator,
we have to use the dot (.) operator. This is for a reason: In Maple, the star operator is reserved for
commutative structures.
Since we all know that matrix multiplication is not commutative (I mean, in general), it makes sense that
we cannot use the * operator. So, here we go:
> A.Av;


1 0 0 0


 0 1 0 0 




 0 0 1 0 


0 0 0 1
OK, that was clear. Let’s now learn how to use lists! A list is just a sequence put into square brackets
> L := [1,2,3,4,5];
L := [1, 2, 3, 4, 5]
Access goes from 1 to 5:
> L[1];
1
> L[2];
2
> L[3];
3
> L[4];
4
> L[5];
45
5
We can change an entry in the list using the assignment operator :=
> L[1] := 2;
L1 := 2
> L;
[2, 2, 3, 4, 5]
How can we append? Our first guess is this
> L := [L,6];
L := [[2, 2, 3, 4, 5], 6]
Hmm, that was’t what we wanted. Here is the solution. Let’s first restore L:
> L := [1,2,3,4,5];
L := [1, 2, 3, 4, 5]
Its a bit tricky, we need to get the contents of the list first, and then add one more entry and make it a list.
At first, we ask for the contents of the list, which is a sequence
> op(L);
1, 2, 3, 4, 5
Now we add an element and make another list:
> [op(L),6];
[1, 2, 3, 4, 5, 6]
We can have a loop create a list as long as we wish. We start with an empty list
> L := [];
L := []
> for i from 1 to 10 do
> L := [ op(L), i ]:
> end;
L := [1]
L := [1, 2]
L := [1, 2, 3]
L := [1, 2, 3, 4]
L := [1, 2, 3, 4, 5]
L := [1, 2, 3, 4, 5, 6]
L := [1, 2, 3, 4, 5, 6, 7]
L := [1, 2, 3, 4, 5, 6, 7, 8]
L := [1, 2, 3, 4, 5, 6, 7, 8, 9]
L := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Uhh, what was that. That was one line of output for each execution of the loop body. Maybe that is too
much output for you. Turning the ”;” to a ”:” after the end prohibits output:
> L := []:
for i from 1 to 10 do
> L := [ op(L), i ]:
> end:
> L;
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
There is a quick way to generate repeated elements in lists. For example, 0$10 would generate 10 entries 0
> L := [3$7];
L := [3, 3, 3, 3, 3, 3, 3]
46
Lab 1
Problem # 1
The Fibonacci sequence 1, 1, 2, 3, 5, 8, 13, 21, ... is defined as follows: f1 = 1, f2 = 1, fi = fi−1 + fi−1 for i ≥ 3.
Create a list with the first 20 Fibonacci numbers using a for loop (use the help function to figure out how
for loops work).
Problem # 2
The Chebychev polynomial Ti (x) is defined as T0 = 1, T1 = x, Ti = 2xTi−1 − Ti−2 for i ≥ 2. Create a list of
the first 5 Chebychev polynomials using a for loop. Note: Your cannot access the zeroth element of a list,
hence you might have to store Ti in the (i + 1)-th list position.
Problem # 3
The Pascal Triangle is the following array of numbers:
1
1
1
1
1
1
1
1
2
3
4
5
6
1
3
6
10
15
1
4
10
20
1
5
15
1
6
1
Figure out what is going on and describe formally the value in the (i, j)-th position. Then write a Maple
program which computes the Pascal triangle of size 10 × 10. Hint 1: you may want to read the help pages
about matrices for storing the data. Alternately, you may use a list of lists. Hint 2: If you are using “word”
to type up your lab, you can export the matrix as excel file and then include that into your word document.
47
2.2
Lecture 2: Plotting
Lecture 2
>
plot(sin(t),t);
>
plot(sin(t),t=-10*Pi..10*Pi);
You can click on the plot and resize the window, for example. You can have two plots in one:
>
plot([sin(t), cos(t)], t=-Pi..Pi);
48
Another way to define a function:
>
f := x -> exp(-x^2)*sin(Pi*x^3);
2
f := x 7→ e−x sin π x3
>
plot(f,-2..2);
49
You can draw the plot over the full x-axis to infinity:
>
plot(f, 0..infinity);
50
Multiple plots again:
>
plot([f(x), exp(-x^2),-exp(-x^2)],x=-2..2);
For folks who use unix/linux etc. You can export Maple plots in PostScript files:
>
plotsetup(PostScript, plotoutput="test.eps", plotoptions="portrait,noborder,height=3in,width=4.5in
>
plot([f(x), exp(-x^2),-exp(-x^2)],x=-2..2);
\begin{Maple Error}{\normalsize{Error, Error in device driver: plot terminated}}\end{Maple Error}
Now a file ”test.eps” has been created. To get back to normal mode use do the following:
>
plotsetup(default);
We can do a parametric x/y - plot:
>
plot([sin(t), cos(t), t=-Pi..Pi]);
51
>
plot([sin(t),cos(2*t+Pi/2),t=0..10*Pi]);
You may play around with the constants ! Next, a polar coordinate plot:
52
>
plot([sin(4*x),x,x=0..2*Pi],coords=polar,thickness=3);
Let’s do a point plot:
>
plot(sin,0..Pi, scaling=constrained, style=point,symbol=circle,symbolsize=20);
Another way is creating a list first:
>
>
l := [[ n, sin(n*Pi/20)] $n=0..20]:
plot(l, x=0..21, style=point,symbol=circle);
53
We need to load a ”package”
>
with(plots):
\begin{Maple Warning}{\normalsize{Warning, the name changecoords has been redefined}}\end{Maple Warning}
\begin{Maple Warning}{\normalsize{Warning, the previous binding of the name arrow has been removed and it now ha
Implicit plots of algebraic curves
>
implicitplot(y^2=x*(x+1)*(2*x+1)/6,x=-3..3,y=-4..4);
54
It does not look nice. Let’s do a field plot:
>
fieldplot([cos(x),cos(y)],x=-2*Pi..2*Pi,y=-2*Pi..2*Pi, arrows=SLIM, grid=[11,11], axes=boxed);
55
3D plots:
>
plot3d(sin(x)*cos(y),x=-Pi..Pi,y=-Pi..Pi);
You can click on the plot and strech it around to make it look nice.
We want to plot the quadratic surface xˆ2+yˆ2-zˆ2=1.
This is a ”hyperboloid of one sheet” also known from atomic power plants.
We first try to solve it for z, i.e. z = sqrt(xˆ2+yˆ2-1.
plot3d(sqrt(x^2+y^2-1),x=-3..3,y=-3..3);
56
It does not look good. To improve, we need to choose better coordinates. We need to load another packages,
however
>
with(plottools):
>
cylinderplot(1,theta=0..2*Pi,z=-1..1);
OK, let’s do the math first, if xˆ2 + yˆ2 = 1+zˆ2 and for a given z we have an x/y plane where the ray
with angle theta and length r projects onto the x and y axis with x and y, respectively, by Pythagoras, we
have xˆ2 + yˆ2 = rˆ2, i.e. r = sqrt(xˆ2+yˆ2) = sqrt(1 + zˆ2) by the above. Hence:
>
cylinderplot(sqrt(1+z^2),theta=0..2*Pi,z=-1..1);
57
Aahh, this looks much better! What else is there? Try sphereplot, for example:
>
sphereplot(1,theta=0..2*Pi,phi=0..Pi);
58
Lets make the sphere wobbly:
>
sphereplot(10+sin(10*theta)+cos(10*phi),theta=0..2*Pi,phi=0..Pi);
OK, now for another cylinderplot. This time we plot the real quadric cone with equation xˆ2+yˆ2=zˆ2 or
xˆ2+yˆ2-zˆ2 = 0
>
cylinderplot(z,theta=0..2*Pi,z=-1..1);
59
elliptic paraboloid: xˆ2+yˆ2+z = 0, i.e., r = (xˆ2+yˆ2), so r = sqrt(-z)
>
cylinderplot(sqrt(-z),theta=0..2*Pi,z=-1..1);
60
Hyperbolic paraboloid xˆ2-yˆ2+z = 0. Back to ordinary plots z in terms of x and y:
>
plot3d(x^2-y^2,x=-1..1,y=-1..1);
for more info on quadric surfaces, see http://www.math.umn.edu/ rogness/quadrics/index.shtml
>
with(plottools):
>
with(plots):
\begin{Maple Warning}{\normalsize{Warning, the previous binding of the name arrow has been removed and it now ha
>
cylinderplot(1,theta=0..2*Pi,z=-1..1);
61
OK, let’s do the math first, if xˆ2 + yˆ2 = 1+zˆ2 and for a given z we have an x/y plane where the ray
with angle theta and length r projects onto the x and y axis with x and y, respectively, by Pythagoras, we
have xˆ2 + yˆ2 = rˆ2, i.e., r = sqrt(xˆ2+yˆ2) = sqrt(1 + zˆ2) by the above. Hence
>
cylinderplot(sqrt(1+z^2),theta=0..2*Pi,z=-1..1);
62
We can give the plot a name, i.e. assign it to a variable:
> H := cylinderplot(sqrt(1+z^2),theta=0..2*Pi,z=-2..2):
> display(H); # here it is:
63
Let’s intersect the Hyperboloid with a plane. At first, here comes a plane:
>
plot3d(1,x=-2..2,y=-2..2);
>
P := plot3d(1,x=-2..2,y=-2..2):
>
display(H,P);
64
We need labels for the corrdinate axes. Let’s replot with labels:
> H := cylinderplot(sqrt(1+z^2),theta=0..2*Pi,z=-2..2,axes=BOXED,labels=[x,y,z]):
> display(H);
65
>
display(H,P);
We need to rotate the plane around the y axis by 90 degrees = 9*Pi/18 The rotate command can do that. It
is called rotate(object to rotate, alpha, beta, gamma) where alpha, beta, gamma are the angles of rotation
around the x, y, z axes, resp.
>
R := rotate(P,0,9*Pi/18,9*Pi/18):
>
display(H,R);
66
>
display(H,R);
We can see the plane at distance 1 from the z-axis. It intersects the Hyperboloid in two lines. Let’s see if we
can get a hold of those two lines: The right thing to do is to define a spacecurve, which is just a parametrized
67
curve in 3 space. The command is
spacecurve([x(t),y(t),z(t)],t=-...);
Let’s do the math first. The curve is in the plane y=1, i.e., we substitute y=1 into the equation xˆ2+yˆ2zˆ2=1
and get
xˆ2=zˆ2, i.e.,
x=+z and x=-z,
so, we may parameterize x(t)=t,y(t)=1,z(t)=+-t
>
C1 := spacecurve([t,1,t],t=-2..2,color=red,thickness=3):
>
C2 := spacecurve([t,1,-t],t=-2..2,color=red,thickness=3):
>
display(H,R,C1,C2);
Let’s see the hyperbolas. We cut with a plane x=0 by substituting in the equation xˆ2+yˆ2-zˆ2=1. This
gives yˆ2=zˆ2+1, i.e., y = +- sqrt(1+zˆ2), i.e., x(t)=0,y(t) =sqrt(1+zˆ2),z(t) = t.
>
C3 := spacecurve([0,sqrt(1+t^2),t],t=-2..2,color=red,thickness=3):
>
display(H,C3);
68
Let’s draw 4 hyperbolas, one in each direction. We do that using a list (recall how we handled lists in the
first lecture?)
>
>
L := []: for i from 0 to 4 do
L := [ op(L), rotate(C3,0,0,i*9*Pi/18)]:
end:
>
display(H,L);
>
69
70
Lab 2
Problem # 1
(i) Plot the Hyperboloid of one sheet x2 + y 2 − z 2 = 1.
(ii) Plot the Hyperboloid of two sheets x2 + y 2 − z 2 = −1.
Problem # 2
Here is a plot. Find the command to recreate it:
Problem # 3
Plot the first 5 Chebychev polynomials in one plot. Hint: You may want to create a list of the polynomials
first.
Problem # 4
The “tribonacci” numbers are defined as
t1 = 1,
t2 = 1,
t3 = 1,
ti = ti−1 + ti−2 + ti−3 for i ≥ 4.
Compute the first 20 tribonacci numbers. Compute the ratio ti /ti−1 for increasing i. Does it converge? Plot
a graph to support your answer.
71
2.3
Lecture 3 and 4: Exploring Matrices
>
with(geometry):
>
p := point(’A’,0,0);
p := A
>
draw(p,printtext=true);
>
A:=<<1|2>,<3|4>>;
"
1
2
3
4
1
2
3
4
#
A :=
>
A:=<<1,3>|<2,4>>;
"
#
A :=
>
N := 26;
N := 26
>
P := array(0..N-1);
>
P[0];
P0
>
>
for i from 0 to N - 1 do
P[i] := [evalf(cos(2*Pi*i/N)),evalf(sin(2*Pi*i/N))]:
end:
>
print(P);
>
854560257, 0.4647231719], 12 = [−0.9709418174, 0.2393156643], 13 = [−1.0, 0.0], 14 = [−0.9709418174, −0.2393156643], 15 = [−0.8854560257, −
72
plotpoints := proc(N,P,label)
local i, A;
> A := array(0..N);
> for i from 0 to N - 1 do
> A[i] := point(label||i,P[i][1],P[i][2]);
> end:
> A[N] := point(’O’,0,0):
> return A;
> end;
for i from 0 to N − 1 do
A[i] := geometry : −geometry(label||i, P [i][1], P [i][2])
>
>
:= array(0..N );
>
PP := plotpoints(N,P,’x’);
PP := A
>
draw(PP,printtext=true);
>
Origin := point(’O’,0,0);
Origin := O
>
draw(PP,printtext=true);
73
end do; ;
A[N ] := geometry : −
(0..N − 1);
mapping := proc(N,A,P)
local i,Q,a,b,c,d;
Q := array(0..N-1):
for i from 0 to N-1 do
a := P[i][1]:
b := P[i][2]:
c := A[1,1]*a+A[1,2]*b;
d := A[2,1]*a+A[2,2]*b;
Q[i] := [c,d];
end;
return Q;
end;
>
for i from 0 to N − 1 do
>
a := P [i][1];
b := P [i][2];
c := A[1, 1] ∗ a + A[1, 2] ∗ b;
d := A[2, 1] ∗ a + A[2, 2
Q := mapping(N,A,P);
Q := Q
>
print(Q);
181, −0.797475389], 12 = [−0.4923104888, −1.955562795], 13 = [−1.0, −3.0], 14 = [−1.449573146, −3.870088109], 15 = [−1.814902370, −4.51526
74
plotpoints := proc(N,P,Q,label1,label2)
local i, A;
> A := array(0..2*N);
> for i from 0 to N - 1 do
> A[i] := point(label1||i,P[i][1],P[i][2]);
> end:
> for i from 0 to N - 1 do
> A[N+i] := point(label2||i,Q[i][1],Q[i][2]);
> end:
> A[2*N] := point(’O’,0,0):
> return A;
> end;
A[i] := geometry : −geometry(label1||i, P [i][1], P [i][2]) end do; ; for i from 0 to N − 1 do
>
>
>
PP := plotpoints(N,P,Q,’x’,’y’);
PP := A
>
draw(PP,printtext=true);
>
A := <<1|1>,<0|1>>;
75
A[N i] := geometry : −geometry(label
i][2])
"
1
1
0
1
#
A :=
>
Q := mapping(N,A,P);
Q := Q
>
PP := plotpoints(N,P,Q,’x’,’y’);
PP := A
>
draw(PP,printtext=true);
plotpoints := proc(N,P,Q,label1,label2)
local i, A;
A := array(0..3*N);
for i from 0 to N - 1 do
A[i] := point(label1||i,P[i][1],P[i][2]);
end:
for i from 0 to N - 1 do
A[N+i] := point(label2||i,Q[i][1],Q[i][2]);
end:
for i from 0 to N - 1 do
A[2*N+i] := line(l||i,[label1||i,label2||i]);
end:
A[3*N] := point(’O’,0,0):
return A;
end;
for i from 0 to N − 1 do
A[N i] := geometry : −geometry(label2||i, Q[i][1], Q[i][2])
>
end do; ;
>
A := <<1|2>,<3|4>>;
"
1
2
3
4
A :=
>
Q := mapping(N,A,P);
Q := Q
>
PP := plotpoints(N,P,Q,’x’,’y’):
>
draw(PP,printtext=true);
76
#
end do; ;
for i from 0 to N −
>
sqrt(Q[5][1]^2+Q[5][2]^2);
5.293984412
>
evalf(5/2+sqrt(33)/2);
>
P[5];
5.372281324
[0.3546048868, 0.9350162428]
>
>
r1 := 5/2+sqrt(33)/2;
√
r1 := 5/2 + 1/2 33
B := A-<<r1|0>,<0|r1>>;
"
√
−3/2 − 1/2 33
2
3
√
3/2 − 1/2 33
B :=
>
#
with(LinearAlgebra):
\begin{Maple Warning}{\normalsize{Warning, the name CrossProduct has been rebound}}\end{Maple Warning}
>
N :=NullSpace(B);
("
N :=
4 3+
√
1
>
N[1];
77
−1 #)
33
"
4 3+
√
33
−1 #
1
>
x:= N[1][1];
x := 4 3 +
>
√
33
−1
y := N[1][2];
y := 1
>
>
n := sqrt(x^2+y^2):
evalf(1/n * N[1]);
"
0.4159735576
0.9093767088
78
#
Lab 3 and 4
Problem # 1
Choose your favorite 2 × 2 matrix and plot the images of N points equidistant on the unit circle as in the
lecture. Find the egenvalues and eigenvectors as in the lecture.
Problem # 2
Legendre Polynomials satisfy the following recurrence relation
L0 (x) = 1
L1 (x) = x
Ln (x) =
(n − 1)(xLn−1 (x) − Ln−2 (x))
+ xLn−1 (x),
n
n = 2, 3, · · · , .
Write a procedure to compute the Legendre polynomials Ln (x). Use the array(0..40) command to allocate
R1
storage for the polynomials. Test your procedure to compute L7 (x) and L40 (x). Compute −1 Ln (x)Lm (x)dx
for m 6= n.
Problem # 3
- Assign the variable name
√ a to the number 2π/5 and then use evalf to compute the decimal approximations for a2 , 1/a, a, a1.3 , sin(a), and tan(a). Don’t forget to assign a variable to each of these
values.
- The number of significant digit can be changed from the default value of 10 to some other number,
such as 20, with the command Digits:=20;. Repeat the previous exercise with 20 significant digits.
Problem # 4
- Expand the following expressions.
(a) (x2 + 2x − 1)3 (x2 − 2)
(b) sin(x − 2y) cos(2x − y)
- Factor the expression x2 + 3x + 2. What happens if this expression is changed to x2 + 3.0x + 2.0?
- Simplify
3x
2x2
+ 2
3
x −1 x −1
Problem # 5
2
Plot the function (x−25)
+ cos(2πx) for 0 ≤ x ≤ 49. Try the option numpoints=2000 to improve the figure.
10
Explain what is going on.
79
2.4
Lecture 5: Sierpinski Triangles
Lecture 5
We start with a triangle. For us, a triangle is a list, a list of points. A point is itself a list, a list of coordinates
(namely, x and y coordinates). So, a point at (0,0):
> P := [0,0];
P := [0, 0]
Another point at (1,0):
> Q := [1,0];
Q := [1, 0]
Another point at (0.5,1):
> R := [0.5,1];
R := [0.5, 1]
And now a triangle with these points as vertices:
> PQR := [P, Q, R];
PQR := [[0, 0], [1, 0], [0.5, 1]]
Now let’s plot the thing:
> plots[polygonplot]([PQR], axes=none,
> color=black, scaling=constrained);
Now we want to transform the triangle. The first step is to scale it down by 0.5, that gives
> small1 := [.5*P,.5*Q,.5*R];
small1 := [[0.0, 0.0], [0.5, 0.0], [0.25, 0.5]]
Next, we want to translate it by 0.5 in the direction of the x-axis:
> small2 := [[0.5,0],[1,0],[.75,0.5]];
small2 := [[0.5, 0], [1, 0], [0.75, 0.5]]
Scale the original triangle by 0.25 along the x-axis and by 0.5 along the y axis:
> small3 := [[0.25,0.5],[0.75,0.5],[0.5,1]];
small3 := [[0.25, 0.5], [0.75, 0.5], [0.5, 1]]
Now a list of all three triangles:
> L :=[small1, small2, small3];
L := [[[0.0, 0.0], [0.5, 0.0], [0.25, 0.5]], [[0.5, 0], [1, 0], [0.75, 0.5]], [[0.25, 0.5], [0.75, 0.5], [0.5, 1]]]
80
Let’s plot it:
> plots[polygonplot](L, axes=none,
> color=black, scaling=constrained);
Call this object Sierpinski(1). Sierpinski(2) would be to do the scaling and shifting again, once for each
triangle in the list. This gives us 3*3 = 9 triangles. The idea is to let Maple do the work. The right thing
to do is to write a procedure. This procedure takes a triangle, scales it and shifts it. Let s be the scaling
factor (here 0.5) let x and y be the shift along the x and y axes, respectively. Here we go:
> transform := proc(T,s,x,y)
> return [
> [T[1][1]*s+x,T[1][2]*s+y],
> [T[2][1]*s+x,T[2][2]*s+y],
> [T[3][1]*s+x,T[3][2]*s+y]];
> end:
Ok let’s try it, we give it the original triangle, and the scale and x/y shift:
> T := PQR;
T := [[0, 0], [1, 0], [0.5, 1]]
> transform(T,0.5,0,0);
[[0.0, 0.0], [0.5, 0.0], [0.25, 0.5]]
> transform(T,0.5,0.5,0);
[[0.5, 0.0], [1.0, 0.0], [0.75, 0.5]]
> transform(T,0.5,0.25,0.5);
[[0.25, 0.5], [0.75, 0.5], [0.50, 1.0]]
OK, that’s good. Now let’s try to write a procedure Sierpinski:
> Sierpinski := proc(n)
> local T,L;
> T := [[0,0],[1,0],[0.5,1]];
> transform(T,0.5,0,0);
> transform(T,0.5,0.5,0);
> transform(T,0.5,0.25,0.5);
> end;
nski := proc(n)local T, L; T := [[0, 0], [1, 0], [.5, 1]]; transform(T, .5, 0, 0); transform(T, .5, .5, 0); transform(T, .5, .25, .5)end p
> Sierpinski(1);
[[0.25, 0.5], [0.75, 0.5], [0.50, 1.0]]
81
Oops, that was just one triangle! Yes, we need to put the triangles in a list, that’s what L is good for:
Sierpinski := proc(n)
local T,L;
> T := [[0,0],[1,0],[0.5,1]];
> L := [transform(T,0.5,0,0),
> transform(T,0.5,0.5,0),
> transform(T,0.5,0.25,0.5)];
> end;
ski := proc(n)local T, L; T := [[0, 0], [1, 0], [.5, 1]];
local T, L, i;
>
>
>
L := [transform(T, .5, 0, 0), transform(T, .5, .5, 0), transform(T, .5, .25, .5)]end
L := Sierpinski(1);
L := [[[0.0, 0.0], [0.5, 0.0], [0.25, 0.5]], [[0.5, 0.0], [1.0, 0.0], [0.75, 0.5]], [[0.25, 0.5], [0.75, 0.5], [0.50, 1.0]]]
>
>
plots[polygonplot](L, axes=none,
color=black, scaling=constrained);
OK, that works. But how do we get to the next level? How do we make each triangle become three triangles?
Let’s try by putting in a for loop:
Sierpinski := proc(n)
local T,L,i;
> T := [[0,0],[1,0],[0.5,1]];
> for i to n do
> L := [transform(T,0.5,0,0),
> transform(T,0.5,0.5,0),
> transform(T,0.5,0.25,0.5)];
> end;
> end;
T := [[0, 0], [1, 0], [.5, 1]]; for i to n do
>
>
>
L := [transform(T, .5, 0, 0), transform(T, .5, .5, 0), transform(T, .5, .25, .5)]
Sierpinski(1);
[[[0.0, 0.0], [0.5, 0.0], [0.25, 0.5]], [[0.5, 0.0], [1.0, 0.0], [0.75, 0.5]], [[0.25, 0.5], [0.75, 0.5], [0.50, 1.0]]]
Hmm, nothing happened. Why? Well, in the for loop, we need to run throuh all the triangles in L and do
the transform. Hence we need another for loop. Remember that the length of a list was not length? Right?
It was nops. So we need something like for k to nops(L); Also, we need a second list where we put our
transformed stuff in. Call that list M. Once we are finished with creating M, we let the new L be equal to
M. This gives:
82
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
k to nops(L) do
Sierpinski := proc(n)
local L,M,i,k;
L := [[[0,0],[1,0],[0.5,1]]];
for i to n do
M := [];
for k to nops(L) do
M := [op(M),
transform(L[k], 0.5,0,0),
transform(L[k], 0.5,0.5,0),
transform(L[k], 0.5,0.25,0.5)];
end;
L := M;
end;
plots[polygonplot]([L], axes=none,
color=black, scaling=constrained)
end;
M := [op(M ), transform(L[k], .5, 0, 0), transform(L[k], .5, .5, 0), transform(L[k], .5, .25, .5)]
>
Sierpinski(1);
>
Sierpinski(2);
>
Sierpinski(3);
83
end do; ;
L
>
Sierpinski(4);
>
Sierpinski(5);
>
Sierpinski(6);
84
>
Sierpinski(7);
>
Sierpinski(8);
85
Lab 5
Problem # 1
(i) How many black triangles are drawn by calling Sierpinski(n)?
(ii) What is the ratio of black area in the triangle after a call to Sierpinski(n)? Does that ratio converge
as n goes to infinity?
(iii) Apparently the Sierpinski triangle is not quite eqilateral (it is slightly too high). Can you fix the code
to make it equilateral?
Problem # 2
(i) Write a Maple program that draws the n-th iteration of Helga von Koch’s snowflake curve:
(ii) Compute the length of the curve in the n-th step. Does it converge as n goes to infinity?
Problem # 3
(i) Fill in the missing entries to complete Pascal’s triangle (we only use the upside triangles):
(ii) Give a rule as to which triangles must be colored in order to retrieve Sierpinki’s triangle from Pascal’s
triangle (Sierpinski meets Pascal).
Pk
i
(iii) If n is an integer, write n =
ni ∈ {0, 1} (we call this the binary expansion of n)
i=0 ni 2 with P
k
Similarly, for another integer m, we write m = i=0 mi 2i . Explain how Lucas formula
Y
k n
ni
≡
mod 2
m
mi
i=0
n
explains the “mod 2” pattern of the binomial coefficient m
in terms of the binary expansions of n
and m.
86
2.5
Lecture 6: Basic Cryptography
Lecture 6
Some Cryptography:
> with(StringTools):
> Map( Capitalize, "This is a test." );
‘‘THIS IS A TEST.’’
> Map( LowerCase, %);
‘‘this is a test.’’
> convert("Test string", ’bytes’);
>
[84, 101, 115, 116, 32, 115, 116, 114, 105, 110, 103]
convert([65,66,67], ’bytes’);
>
“ABC 00
convert("abcdefghijklmnopqrstuvwxyz", ’bytes’);
[97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122]
> convert("ABCDEFGHIJKLMNOPQRSTUVWXYZ", ’bytes’);
[65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90]
irem(a, b) gives the remainder r of a upon division by b, i.e., the r in a = q * b + r with r between 0 and b
- 1.
> irem(17,5);
2
> irem(-1,5);
−1
The Caesar cipher is the following:
Each letter in the ppleintext is replaced by the letter following r positions later in the alphabet.
If r=3, for instance, we replace A by D, B by E etc. We consider the alphabet closed cyclically, i.e. the
successor of Z is A.
Hence, we encode W as Z, X ans A, Y as B, Z as C.
> caesar := proc(s::string, shift::integer)
> local S, l, i, c;
> S := convert(s,’bytes’);
> l := nops(S);
> for i to l do
> c := S[i];
> if c >= 97 and c <= 122 then
> c := c - 97 + shift;
> c := irem(c, 26);
> if c < 0 then c := c + 26; end;
> S[i] := 97 + c;
> end;
> end;
> return convert(S,’bytes’);
> end:
An example of encryption:
> caesar("abcdefghijklmnopqrstuvwxyz", 3);
“defghijklmnopqrstuvwxyzabc 00
Decryption is done using the negative shift:
87
>
caesar(%, -3);
“abcdefghijklmnopqrstuvwxyz 00
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
vigenere_cipher := proc(s::string, k::string)
local S, l, K, kl, i, j, c, d;
S := convert(s,’bytes’);
l := nops(S);
K := convert(k,’bytes’);
kl := nops(K);
for i to l do
j := irem(i, kl) + 1;
c := S[i];
d := K[j];
if c >= 97 and c <= 122 then
c := c - 97;
c := c + d;
c := irem(c, 26);
if c < 0 then c := c + 26; end;
S[i] := 97 + c;
end;
end;
return convert(S,’bytes’);
end:
p := "Shake and quiver, little tree, Throw gold and silver down to me";
p := ‘‘Shake and quiver, little tree, Throw gold and silver down to me’’
c := vigenere_cipher(p, "verysecret");
c := ‘‘Srrvb kkp nezgbm, xwqdcp obbq, Tyclr daza rya cfxjbb olrx fc wv’’
vigenere_decipher := proc(s::string, k::string)
local S, l, K, kl, i, j, c, d;
S := convert(s,’bytes’);
l := nops(S);
K := convert(k,’bytes’);
kl := nops(K);
for i to l do
j := irem(i, kl) + 1;
c := S[i];
d := K[j];
if c >= 97 and c <= 122 then
c := c - 97;
c := c - d;
while c < 0 do
c := c + 26;
end;
c := irem(c, 26);
S[i] := 97 + c;
end;
end;
return convert(S,’bytes’);
end:
88
vigenere_decipher(c, "verysecret");
‘‘Shake and quiver, little tree, Throw gold and silver down to me’’
> p := "I have seen too much not to know that the impression of a woman may be more valuable
than the conclusion of an analytical reasoner.";
ve seen too much not to know that the impression of a woman may be more valuable than the conclusion of an analytical
> vigenere_cipher(p, "arthurdoyle");
jibg fob ibtl gyf gy rest dtag pov ffzdefceve ly m jyihe jti br ivii okxunlhl xetx tuo jfrzeeeibx vw xg mnnvuazgxe den
> S := convert(p,’bytes’);
>
1, 115, 115, 105, 111, 110, 32, 111, 102, 32, 97, 32, 119, 111, 109, 97, 110, 32, 109, 97, 121, 32, 98, 101, 32, 109, 111, 114, 101, 32, 118, 97, 108, 117, 97, 98,
> S[1] := 100;
\begin{Maple Error}{\normalsize{Error, assigning to a long list, please use Arrays}}\end{Maple Error}
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
T := Array(S);
T := RTABLE (590368, anything, Array, rectangular , Fortran order , [], 1, 1 . . . 131)
T[1];
73
vigenere_cipher := proc(s::string, k::string)
local S, T, L, l, K, kl, i, j, c, d;
S := convert(s,’bytes’);
T := Array(S);
l := nops(S);
K := convert(k,’bytes’);
kl := nops(K);
for i to l do
j := irem(i, kl) + 1;
c := T[i];
d := K[j];
if c >= 97 and c <= 122 then
c := c - 97;
c := c + d;
c := irem(c, 26);
if c < 0 then c := c + 26; end;
T[i] := 97 + c;
end;
end;
L := [];
for i to l do
L := [op(L),T[i]];
end;
return convert(L,’bytes’);
end:
vigenere_cipher(p, "arthurdoyle");
jibg fob ibtl gyf gy rest dtag pov ffzdefceve ly m jyihe jti br ivii okxunlhl xetx tuo jfrzeeeibx vw xg mnnvuazgxe den
>
89
Lab 6
Problem # 1
The “Nero” cipher exchanges a and z, b and y, c and x etc.
(i) Write a procedure to encrypt using the Nero cipher.
(ii) Take your favorite text and encrypt it with 7 Caeser, one Nero and 12 more Caesar ciphers. What do
you get?
(iii) How do you decipher it?
(iv) Can you decipher it using only one n-fold Caesar and one Nero step?
Problem # 2
(i) Rewrite the function vigenere decipher() to use an Array (to make it work for long strings.)
(ii) Dcipher the following piece (the key is “jane”) ”Wnv, sv wkxt, vqn jwlz mgut, Mou. Lqgm utep mnxv
Nbvakohbkif op mghgg ya g ahaki sxp uc egoix cqkzrpx cths vak phxqj uc Etdntta”
(iii) Rewrite the functions vigenere cipher and vigenere cipher to also encrypt capital letters. Use this
function the encrypt the text of 2) with the key “jane.”
90
2.6
Lecture 7: Mortgage Calculations
Lecture 7
Consider the following problem:
You have been offered a mortgage of $100, 000 (= P0 ) at I = 6.5% interest (fixed) over 30 years.
How high is the monthly payment M ?
Let us start by modeling the problem:
Modeling the Problem
Note that there are N = 360 monthly payments (= 30 × 12).
Let Pi be the outstanding principal at the end of month i (So P0 = $100, 000 the loan amount). It is a
required that PN = P360 = $0, i.e. the loan is paid off in the end. We say that the mortgage is amortized.
The monthly interest rate is Im =
6.5%
12
= .5417% = .005417.
Consider the first month, for example. At the end of the first month we have made the first payment of
$M. During the month, the interest accrued is P0 × Im . That is, P0 × Im of the payment goes towards the
interest. We hope that M is higher than this amount, so that the remaining funds can be applied towards
the principal. That is, the new principal at the end of month 1 is computed as
P1 = P0 − (M − P0 × Im ) = P0 × (1 + Im ) − M.
For the second month, the computation is similar. We obtain
P2 = P1 × (1 + Im ) − M.
In general, we have the recurrence relation
Pi+1 = Pi × (1 + Im ) − M
i>0
with the initial condition P0 = $100, 000 and the terminal condition PN = $0.
It remains to solve these equations for M.
Solving the Problem
We make use of a tool from Combinatorics called a generating function. Namely, we introduce the polynomial
P (x) = P0 + P1 x + P2 x2 + · · · + P360 x360
whose coefficients are the unknown coefficients Pi . This polynomial can be written in a more compact way
as
360
X
P (x) =
Pi xi .
i=0
Such a polynomial is known as a generating function. It’s sole purpose is to record the coefficients Pi . We will
never really substitute anything for x and evaluate the polynomial. Here, since we record the outstanding
principal, we call P (x) the principal generating function. Note that P360 = 0, so that the last term really
isn’t there, so that
359
X
P (x) =
Pi xi .
i=0
91
We compute
P (x) − P0
=
360
X
Pi xi =
i=1
=
359
X
359
X
Pi+1 xi+1
i=0
Pi (1 + Im )xi+1 −
i=0
=
359
X
M xi+1
i=0
(1 + Im )x
359
X
Pi xi − M x
359
X
i=0
=
xi
i=0
(1 + Im )xP (x) − M x
359
X
xi
i=0
It follows that
359
X
P (x) 1 − (1 + Im )x = P0 − M x
xi
i=0
i.e.,
P359
P0 − M x i=0 xi
.
P (x) =
1 − (1 + Im )x
Developing the denominator we obtain
P (x) = P0
X
359
X
X
(1 + Im )i xi − M x
(1 + Im )i xi
xj .
i≥0
j=0
i≥0
For n ≤ 360, we can retrieve Pn as the coefficient of xn in this expression. That is,
Pn
=
[xn ]P (x)
= P0 (1 + Im )n − M
n−1
X
(1 + Im )i
i=0
(1 + Im )n − 1
= P0 (1 + Im )n − M
1 + Im − 1
In particular,
0 = P360 = P0 (1 + Im )360 − M
(1 + Im )360 − 1
Im
i.e.,
M
(1 + Im )360 − 1
= P0 (1 + Im )360
Im
i.e.,
M = P0
(1 + Im )360 Im
(1 + Im )360 − 1
Here, we have P0 = $100, 000. We also use α = 1 + Im .
The following MAPLE code can be used to evaluate M. It turns out that M = $632.07. We also compute
the coefficient N M/P0 which is ratio of the anount that the mortgage costs to the loan amount.
Then we tabulate the amortization of the mortgage over the 360 months (only the first 10 months and then
every tenth month is shown for the sake of saving space). Lastly, we plot the principal over the 360 months
and the amount that is applied towards the principal over the 360 months.
92
>
P0 := 100000;
P0 := 100000
>
i := 0.065;
i := 0.065
>
im := i / 12;
im := 0.005416666667
>
alpha := im + 1;
α := 1.005416667
>
N := 360;
N := 360
>
P := Array(1..N+1):
>
M := P0 * alpha^N * im / (alpha^N - 1);
M := 632.0680110
>
M * N / P0;
2.275444840
>
>
>
>
>
>
>
>
>
d := P0;
P[1] := d;
for i to N do
d := d * alpha - M;
P[i + 1] := d;
if i <= 10 or irem(i,10)=0 then
print("month ", i, " principal ", P[i + 1], " reduction ", P[i] - P[i+1]);
end:
end:
93
d := 100000
P1 := 100000
‘‘month ’’, 1, ‘‘ principal ’’, 99909.59869, ‘‘ reduction ’’, 90.40131
‘‘month ’’, 2, ‘‘ principal ’’, 99818.70769, ‘‘ reduction ’’, 90.89100
‘‘month ’’, 3, ‘‘ principal ’’, 99727.32439, ‘‘ reduction ’’, 91.38330
‘‘month ’’, 4, ‘‘ principal ’’, 99635.44609, ‘‘ reduction ’’, 91.87830
‘‘month ’’, 5, ‘‘ principal ’’, 99543.07009, ‘‘ reduction ’’, 92.37600
‘‘month ’’, 6, ‘‘ principal ’’, 99450.19379, ‘‘ reduction ’’, 92.87630
‘‘month ’’, 7, ‘‘ principal ’’, 99356.81436, ‘‘ reduction ’’, 93.37943
‘‘month ’’, 8, ‘‘ principal ’’, 99262.92913, ‘‘ reduction ’’, 93.88523
‘‘month ’’, 9, ‘‘ principal ’’, 99168.53535, ‘‘ reduction ’’, 94.39378
‘‘month ’’, 10, ‘‘ principal ’’, 99073.63027, ‘‘ reduction ’’, 94.90508
‘‘month ’’, 20, ‘‘ principal ’’, 98095.84123, ‘‘ reduction ’’, 100.17290
‘‘month ’’, 30, ‘‘ principal ’’, 97063.77880, ‘‘ reduction ’’, 105.73312
‘‘month ’’, 40, ‘‘ principal ’’, 95974.43045, ‘‘ reduction ’’, 111.60197
‘‘month ’’, 50, ‘‘ principal ’’, 94824.61650, ‘‘ reduction ’’, 117.79657
‘‘month ’’, 60, ‘‘ principal ’’, 93610.98068, ‘‘ reduction ’’, 124.33502
‘‘month ’’, 70, ‘‘ principal ’’, 92329.98053, ‘‘ reduction ’’, 131.23639
‘‘month ’’, 80, ‘‘ principal ’’, 90977.87686, ‘‘ reduction ’’, 138.52083
‘‘month ’’, 90, ‘‘ principal ’’, 89550.72303, ‘‘ reduction ’’, 146.20960
‘‘month ’’, 100, ‘‘ principal ’’, 88044.35327, ‘‘ reduction ’’, 154.32514
‘‘month ’’, 110, ‘‘ principal ’’, 86454.37058, ‘‘ reduction ’’, 162.89115
‘‘month ’’, 120, ‘‘ principal ’’, 84776.13395, ‘‘ reduction ’’, 171.93262
‘‘month ’’, 130, ‘‘ principal ’’, 83004.74472, ‘‘ reduction ’’, 181.47595
‘‘month ’’, 140, ‘‘ principal ’’, 81135.03232, ‘‘ reduction ’’, 191.54900
‘‘month ’’, 150, ‘‘ principal ’’, 79161.53923, ‘‘ reduction ’’, 202.18116
‘‘month ’’, 160, ‘‘ principal ’’, 77078.50497, ‘‘ reduction ’’, 213.40348
‘‘month ’’, 170, ‘‘ principal ’’, 74879.84933, ‘‘ reduction ’’, 225.24870
‘‘month ’’, 180, ‘‘ principal ’’, 72559.15457, ‘‘ reduction ’’, 237.75141
‘‘month ’’, 190, ‘‘ principal ’’, 70109.64678, ‘‘ reduction ’’, 250.94810
‘‘month ’’, 200, ‘‘ principal ’’, 67524.17603, ‘‘ reduction ’’, 264.87728
‘‘month ’’, 210, ‘‘ principal ’’, 64795.19555, ‘‘ reduction ’’, 279.57962
‘‘month ’’, 220, ‘‘ principal ’’, 61914.73960, ‘‘ reduction ’’, 295.09804
‘‘month ’’, 230, ‘‘ principal ’’, 58874.40042, ‘‘ reduction ’’, 311.47782
‘‘month ’’, 240, ‘‘ principal ’’, 55665.30344, ‘‘ reduction ’’, 328.76678
‘‘month ’’, 250, ‘‘ principal ’’, 52278.08158, ‘‘ reduction ’’, 347.01538
‘‘month ’’, 260, ‘‘ principal ’’, 48702.84779, ‘‘ reduction ’’, 366.27690
‘‘month ’’, 270, ‘‘ principal ’’, 44929.16623, ‘‘ reduction ’’, 386.60755
‘‘month ’’, 280, ‘‘ principal ’’, 40946.02180, ‘‘ reduction ’’, 408.06668
‘‘month ’’, 290, ‘‘ principal ’’, 36741.78801, ‘‘ reduction ’’, 430.71693
‘‘month ’’, 300, ‘‘ principal ’’, 32304.19303, ‘‘ reduction ’’, 454.62440
‘‘month ’’, 310, ‘‘ principal ’’, 27620.28387, ‘‘ reduction ’’, 479.85889
‘‘month ’’, 320, ‘‘ principal ’’, 22676.38853, ‘‘ reduction ’’, 506.49405
‘‘month ’’, 330, ‘‘ principal ’’, 17458.07618, ‘‘ reduction ’’, 534.60763
‘‘month ’’, 340, ‘‘ principal ’’, 11950.11496, ‘‘ reduction ’’, 564.28169
‘‘month ’’, 350, ‘‘ principal ’’, 6136.427520, ‘‘ reduction ’’, 595.602844
‘‘month ’’, 360, ‘‘ principal ’’, 0.0441778, ‘‘ reduction ’’, 628.6625162
>
L := [seq([i,P[i]],i=1..N+1)]:
>
plot(L,x=1..N+1,style=point);
94
>
>
L := [seq([i,P[i] - P[i+1]],i=1..N)]:
plot(L,x=1..N+1,style=point);
95
Lab 7
Problem # 1
You have taken out a mortgage of $120, 000 at 7% fixed interest amortized over 30 years with fixed monthly
payments.
(i) How long (in months) will it take you to pay back the first $10, 000?
(ii) How long (in months) will it take you to pay back the last $10, 000?
(iii) After 3 years, you decide to make an extra payment of $2, 000. How much will this shorten your overall
amortization period (in months).
96
2.7
Lecture 8: Magic Squares and Recursion
Lecture 8
Magic Squares
First, what is a magic square?
> A magic square is a ’matrix’ or a 2-dimensional grid of numbers.
Take the simple case
of a 3x3 magic square. Here’s one:> 4
3 8
> 9
5 1
> 2
7 6
> A Magic Square contains a certain bunch of numbers, in this case, 1..9, each of which
has to be filled once into the grid. The ’magic’ property of a Magic Square is that the
sum of the numbers in the rows and columns and diagonals should all be same, in this case,
15.
> Try making a 3x3 magic square yourself.
It’s not that easy. If it was easy, try a 4x4
grid with numbers 1..16. And what about 5x5, 6x6...? That’s where computers come in! Okay,
now, how do we go about programming something we hardly understand. The answer is : brute
force. The computer may not be smart, but it can certainly do something you would take
months to do, and that is, pure calculations - millions and millions of them. To have an
analogy, suppose you are given two identical photos. It would take you just a glance of
the eye to agree that they’re same. The computer, on the other hand, would compare them
dot by dot, pixel by pixel, and then agree that they’re same. In the process, both you
and the computer accomplish the same task in pretty much the same time, but in very different
ways. So, the answer is brute force.
>
>
Okay, we’ve got a bunch of numbers. We’ve got to arrange them in a matrix so that the
sum is equal in all directions. Since we don’t have a clue about any strategy, we’d just
have to........ Try All Possibilities! Yes, and that’s what a computer is meant to do
- brute force.
> Okay, try figuring it out yourself at this stage.
You know everything there is to know
- the concept of magic squares, the need to check all possibilities, and that the answer
lies in recursion. To help ease the complexity, you can make a simple function (besides
the recursive function) to check if a square is magical. So, basically, you’ve got to try
all possibilities and permutations, and for each one, you have to call the function to test
if the square is magical. I seriously suggest you stop at this point, and brainstorm to
extremes. Better yet, just finish the program. It isn’t that tough.
>
Given up? Fine. Having said all that I said, only the heart of the program is left
to explain. The question boils down to, how do we accomplish permuting a set of numbers
(or objects) using recursion? For simplicity sake, we work with a 1-dimensional array.
In the case of a 3x3 square, let’s have a 9-length single-dimensional array. So we have
numbers 1 to 9 and 9 locations to put them into. The permutations would be:> 123456789
> 123456798
> 123456879
> 123456897
> 123456978
> 123456987
> ....
> ....
> 987654321
>
97
Conversion from single to 2-D array is fairly simple, and may be done within the magic-testing
function that we shall call ’TestMagic’.
> As a preliminary exercise, try to program the following sequence...
> 111,112,113,121,122,123,131,132,133,
> 211,212,213,221,222,223,231,232,233,
> 311,312,313,321,322,323,331,332,333.
> ...using For loops.
> Answer:
It’s as simple as:>
>
>
>
>
>
>
>
for i to
for j to
for k to
print(i,
end;
end;
end;
3 do
3 do
3 do
j, k);
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
2,
2,
2,
2,
3,
3,
3,
3,
3,
3,
3,
3,
3,
1,
1,
1,
2,
2,
2,
3,
3,
3,
1,
1,
1,
2,
2,
2,
3,
3,
3,
1,
1,
1,
2,
2,
2,
3,
3,
3,
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
Now, try it using recursion.
Answer: Think of it this way: i loops from 1 to 3. For every value of i, j loops from
1 to 3. For every value of j, k loops from 1 to 3. For every value of k, the values are
displayed. So, basically, these three loops perform very similar functions, which can therefore
be reduced to a single recursive function with a single loop.
>
>
>
A := [0,0,0];
A := [0, 0, 0]
98
cal i; global A;
R := proc(n)
global A;
> local i;
> for i to 3 do
> A[n] := i;
> if n < 3 then
> R(n + 1);
> else
> print(A[1], A[2], A[3]);
> end;
> end;
> end;
for i to 3 do
A[n] := i;
if n < 3 then
>
>
>
R(n1)
else
print(A[1], A[2], A[3])
end if;
R(1);
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
2,
2,
2,
2,
3,
3,
3,
3,
3,
3,
3,
3,
3,
1,
1,
1,
2,
2,
2,
3,
3,
3,
1,
1,
1,
2,
2,
2,
3,
3,
3,
1,
1,
1,
2,
2,
2,
3,
3,
3,
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
A[] is simply an array of integers. The function should be invoked with initial n value
as 1, i.e., R(1). Trace the program to figure out the output.
> For each pass through the loop, the function’s child’s loop is completely executed, by
means of the recursive call. [A child of a given instance is the instance that it creates
and calls.]
> Just in order to confuse you even more, the same function can be written in this way:>
>
A := [0,0,0];
A := [0, 0, 0]
99
end
ocal i; global A;
R := proc(n)
global A;
> local i;
> if n < 4 then
> for i to 3 do
> A[n] := i;
> R(n + 1);
> end;
> else
> print(A[1], A[2], A[3]);
> end;
> end;
if n < 4 then
for i to 3 do
>
>
>
A[n] := i;
R(n1)
end do;
else
print(A[1], A[2], A[3])
R(1);
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
2,
2,
2,
2,
2,
2,
2,
2,
3,
3,
3,
3,
3,
3,
3,
3,
3,
1,
1,
1,
2,
2,
2,
3,
3,
3,
1,
1,
1,
2,
2,
2,
3,
3,
3,
1,
1,
1,
2,
2,
2,
3,
3,
3,
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
Anyway, coming back to our magic squares and our 9-length array which is to be permuted....
We can easily adopt the above functions, with one difference: the numbers should not
repeat. If the numbers were allowed to repeat, we could easily write:
>
>
>
A := [seq(i,i=1..9)];
A := [1, 2, 3, 4, 5, 6, 7, 8, 9]
100
end
nd if; ;
permute := proc(n)
local i;
> global A;
> for i to 9 do
> A[n] := i;
> if n < 9 then
> permute(n + 1);
> else
> #print(A);
> if TestMagic() then
> print(A);
> end;
> end;
> end;
> end:
> A[] is the 9-length array.
> The function should be called with n=1 initially.
Function TestMagic checks whether
the square represented by the array is magical, and displays it if it is so.
> Here is the function TestMagic.
> We let the places be labelled by A in the following way:
> A[1] A[2] A[3]
> A[4] A[5] A[6]
> A[7] A[8] A[9]
> TestMagic := proc()
> global A;
> local i, j, s;
> # test horizontally:
> s := A[1] + A[2] + A[3];
> if s <> 15 then return false; end;
> s := A[4] + A[5] + A[6];
> if s <> 15 then return false; end;
> s := A[7] + A[8] + A[9];
> if s <> 15 then return false; end;
> # test vertically:
> s := A[1] + A[4] + A[7];
> if s <> 15 then return false; end;
> s := A[2] + A[5] + A[8];
> if s <> 15 then return false; end;
> s := A[3] + A[6] + A[9];
> if s <> 15 then return false; end;
> # test diagonally:
> s := A[1] + A[5] + A[9];
> if s <> 15 then return false; end;
> s := A[3] + A[5] + A[7];
> if s <> 15 then return false; end;
> return true;
> end;
s := A[1]A[4]A[7]; if s <> 15 then
return f alse end if; ; s := A[2]A[5]A[8]; if s <> 15 then
return f alse
> Attention, this program takes a lot of time.
> You may want to try small searches first,
> for instance by calling permute(n) with n > 4.
>
>
>
A := [seq(i,i=1..9)];
101
] := i;
A := [1, 2, 3, 4, 5, 6, 7, 8, 9]
>
>
>
>
>
>
>
>
permute(5);
#There is no output, meaning that no Magic Square has been found.
#We may help the program by actually putting in the correct
#first row of the Magic Square we know of:
A[1] := 4;
A1 := 4
A[2] := 3;
A2 := 3
A[3] := 8;
A3 := 8
permute(4);
\begin{Maple Warning}{\normalsize{Warning,
computation interrupted}}\end{Maple Warning}
#However, we must not allow repetition, as per the rules and regulations of magic square
authorities and #environmental agencies worldwide. There could be several ways to perform
this check, and it is left open to #you. What I did was: I kept another 9-length array,
which contained information about which number was used, #and which was not.
#E.g.: Say B[] is the extra array. If B[2]=0, then, number 2 is still free. If B[2]=1,
then, number 2 is already #used. Whenever we ’go to’ a recursive call and ’come back’ from
a recursive call, we should update this array. #One possible algorithm could be:> A := [seq(i,i=1..9)];
>
A := [1, 2, 3, 4, 5, 6, 7, 8, 9]
>
B := [seq(0,i=1..9)];
B := [0, 0, 0, 0, 0, 0, 0, 0, 0]
permute := proc(n)
> global A, B;
> local i;
> for i to 9 do
> if B[i] = 0 then
> A[n] := i;
> B[i] := 1;
> if n < 9 then
> permute(n + 1);
> else
> if TestMagic() then
> print(A);
> end;
> end;
> B[i] := 0;
> end;
> end;
> end;
B[i] := 1;
if n < 9 then
> permute(1);
>
permute(n1)
[2, 7, 6, 9, 5, 1, 4, 3, 8]
[2, 9, 4, 7, 5, 3, 6, 1, 8]
102
else
if TestMagic() then
print(A)
[4, 3, 8, 9, 5, 1, 2, 7, 6]
[4, 9, 2, 3, 5, 7, 8, 1, 6]
[6, 1, 8, 7, 5, 3, 2, 9, 4]
[6, 7, 2, 1, 5, 9, 8, 3, 4]
[8, 1, 6, 3, 5, 7, 4, 9, 2]
[8, 3, 4, 1, 5, 9, 6, 7, 2]
0
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
We found 8 Magic Squares:
#1:
2 7 6
9 5 1
4 3 8
#2:
2 9 4
7 5 3
6 1 8
#3:
4 3 8
9 5 1
2 7 6
#4:
4 9 2
3 5 7
8 1 6
#5:
6 1 8
7 5 3
2 9 4
#6:
6 7 2
1 5 9
8 3 4
#7:
8 1 6
3 5 7
4 9 2
#8:
8 3 4
1 5 9
6 7 2
103
Are they really different? Notice: (4,3,8) seems to occure somewhere in each square.
Note the way I set and reset the value of B[i]. For all deeper recursive instances of
the function, value of B[i] is 1. And when we come back, we undo this change. Strictly
speaking, the same concept is used while changing the value of variable n. The value of
n sent to the child instance is different from the value of n in the current instance. And
upon returning from the child instance, the value of n is reset to its old value. (This
is taken care of automatically by the passing of parameters between the calls, so we don’t
have to bother explicitly changing the value of n.)
> The rest is left to you. Try the program, and taste the results yourself.
There are
totally 8 solutions for the 3x3 matrix with numbers 1..9. Did you get them all?
> We have worked out this problem by realizing that we need to find all permutations of
the numbers 1..9, and for each permutation, check if it satisfies the condition. There’s
another way of looking at the same thing, which is a common viewpoint when talking about
recursion. It is called ’BackTracking’. In effect, what our program does is, when it finds
(at the 9th recursion) that a square is not magical (say), it ’goes back’ to the previous
instance of the function, and even more back if needed. This is called BackTracking and
is used in all recursive-problem-solving programs.
> Even if you own a 800MHz m/c, you may have noticed that the calculation took at least
a few seconds, maybe longer. This is because the algorithm is not very efficient. It is
possible to get all the results in under a second on any machine, if we tweak this algorithm
here and there. That’s what we’ll do next.
> Tweak
> If you observe (and imagine) a bit...
okay, more than just a bit.... you will realize
that a LOT of the possibilities we test are actually quite useless. The first state is:
> 1
2 3
> 4
5 6
> 7
8 9
> or, 1 2 3 4 5 6 7 8 9.
> Now, the begins by permuting 8-9, then 7-8-9, then 6-7-8-9...
which all takes time.
All these are useless until we start permuting the top row, since 1+2+3=6, but we need 15.
Get it? It’s going to take a LOT of permutations before we finally backtrack to 3,2 and
1, which remain as sum 6 all this while. So, this 1-2-3 combination really sucks, and we
should never allow it.
> I wouldn’t be describing this problem if I didn’t know the answer, so here it is:
While
filling the numbers, at every row, we check if the sum is 15. So, before we go on to the
second row (or the 4th element in our 1-D array) we check the sum of the first row - if
it isn’t 15, go back and permute... until the sum is 15. So, now the first row has a sum
15 (done very quickly since we permute only 3 locations) and all those useless permutations
of the other two rows are not attempted. The same should happen for the second row, which
saves some time, but not as much as that for the first row. Finally, after all 9 elements
are inserted, check the columns and diagonals.
> Actually what happens is, if the sum of the first row elms is not 15, it backtracks until
the sum is 15. If the sum is now 15, it ’goes forward’ and checks the second row for sum
15. If second row sum is not 15, it backtracks to try to get the sum as 15. If all permutations
within row 2 are complete, it backtracks to row 1... The following function checks the
sum at every row.
> void Permute(n)
> for i = 1 to 9
> if B[i]=0
// if i is free
> B[i]=1
> A[n]=i
> if (n % 3 = 0) // if n is div by 3
> if RowSum() = 15
> if n<9
104
> Permute(n+1)
> else
// at the end
> TestMagic()
> else
> Permute(n+1) //recurse
> B[i]=0
>
>
Lab 8
Problem # 1
a) Write a function using Recursion to display all anagrams of the word ’RECURSION’. How many did you
get? Are they really all distinct? If no, can you make it so that they are really all distinct? How many do
you get now?
b) Do the same with the word MISSISSIPPI. How many do you get now?
Problem # 2
Write a recursive program to generate the sequence of all permutations of the integers 1,2, up to n (here we
show n=5):
[1, 2, 3, 4, 5]
[1, 2, 3, 5, 4]
[1, 2, 4, 3, 5]
[1, 2, 4, 5, 3]
[1, 2, 5, 3, 4]
[1, 2, 5, 4, 3]
[1, 3, 2, 4, 5]
[1, 3, 2, 5, 4]
...
[5, 4, 3, 2, 1]
Your program should work for any given n.
105
2.8
Lecture 9: Partitions
Lecture 9
In this lecture, we want to discuss how to create partitions of a number.
Before we start, let’s talk a bit more about lists: At fist, here is a range, which is just a sequence:
> 2..3;
2...3
> 1..10;
1 . . . 10
this is how we create a sequence:
> s := seq(i,i=1..10);
s := 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Same thing, but now as a list
> s := [seq(i,i=1..10)];
s := [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Can we do it from 10 downwards?
> s := seq(i,i=10..1);
s :=
No, it does not work. Too bad. The following piece of code produces a list whose elements are decreasing.
> [seq(10+1-i,i=1..10)];
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Yet another way
> ListTools[Reverse]([seq(i,i=1..10)]);
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Alternately, we could have loaded the package by using with(listtools);
Let’s use the map command. The map command applies a function to all elements of a list. For example,
we may increase each element in the list by one as follows (here we use the function i -> i+1, I hope you
still remember this notation)
> map( i -> i+1, [seq(i,i=1..10)]);
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
We may also write the function as a procedure, using the proc command:
> map( proc(a) return a + 1; end, [seq(i,i=1..10)]);
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
A procedure always starts with proc() in the parenthesis, we may put one or more arguments (or parameter)
for the procedure as input. The procedure body goes right to the command end which closes the procedure.
We may have a return command inside the procedure, then the procedure is treated as a function, namely
the function which returns the value from the return command. So, in this case, we have a procedure which
takes as arguments an integer a and computes a + 1 as return value. That’s all folks! Let’s say we want to
add some quantity to all emntries of the list, but we want to pass the value of that quantity as a parameter
to the procedure. This is how we do it, we just put that parameter as an additional argument to the map
command.
> map( proc(a,n) return a+n; end, [seq(i,i=1..10)], 3);
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
Here is the additional parameter which gets passed as n to out procedure. In this case, we just want to add
3 to all list elements. OK, now we have another way of creating a list with the numbers downwards
> map( proc(a,n) return n + 1 - a; end, [seq(i,i=1..10)], 10);
106
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
Choose a number n (say 5). A partition of n is an expression of the form
n = a1 + a2 + ... ak with a1 through ak weakly decreasing and ak greater or equal to one.
Here is an example:
5=5=4+1=3+2=3+1+1=2+2+1=2+1+1+1=1+1+1+1+1
is all partitions of the number 5.
It would be nice if we could get maple to create partitions for us.
At first, lets decide on how to represent a partition is maple. For instance, we could use a list which lists
the members of the partition in decreasing order. That is, the partitions of 5 would be
> [5];
[5]
> [4,1];
[4, 1]
> [3,2];
[3, 2]
> [3,1,1];
[3, 1, 1]
> [2,2,1];
[2, 2, 1]
> [2,1,1,1];
[2, 1, 1, 1]
> [1,1,1,1,1];
[1, 1, 1, 1, 1]
How could we create partitions by ourselves? Assume we have decided on the first number a1, say.
Then in order to create all partitions with a1 as first number, we need to create the partitions of n - a1.
Since the parts of the partition are supposed to be weaakly decreasing, we must have a2 less than or equal
to a1.
That is, we need to have a procedure that creates all partitions of n whose parts are less than or equalto
k. If this procedure were available, we would create the first part a1 and then call the procedure for n-a1,
under the condition that the parts used are at most a1. Let part(n,k) be such a procedure. There is the
issue of managing the data. Of course, the output of part(n-a1,a1)
is a list of partitions of n-a1. Example: if a1 = 3 then part(2,3) would produce [2] and [1,1]. In order to
finish the job, we neeed to put a1 (which is 3) in the first place. Lets see how this can be done. Notice first
that the largest possible value for a1 in the call to proc(n,k) is the minimum of n and k (why?).
> [[2],[1,1]];
[[2], [1, 1]]
Say this was the list of partitions produced by part(2,3). Lets see if we can get 3 in the first place to make
the partitions [3,2] and [3,1,1] of 5.
> A := map(proc(L,a1) return [a1,op(L)]; end, [[2],[1,1]], 3);
A := [[3, 2], [3, 1, 1]]
What was that? The procedure part(L,a1) takes L which is a partition of n-a1 and the integer a1 and puts
a1 in the first place.
This is done for all partitions in the list. The actual value of a1 comes from the very end (3 in this case),
which is passed through to the procedure proc as second argument.
The list [[2],[1,1]] was just an example, it has to be replaced by part(n-a1,a1), of course. Also, the integer 3
in the end has to be replaced by a1. If a1 = 2, for instance, we would create all partitions of 3 with largest
element 2. These are [2,1] and [1,1,1]. In this case, we had
107
hen
>
B := map(proc(L,a1) return [a1,op(L)]; end, [[2,1],[1,1,1]], 2);
B := [[2, 2, 1], [2, 1, 1, 1]]
And then we would have to join the two separate lists from the two cases into one. This is how we do it:
> [op(A),op(B)];
[[3, 2], [3, 1, 1], [2, 2, 1], [2, 1, 1, 1]]
Then we need to consider all possibilities for a1 in turn. We want to loop ovar all possibilities for a1 in
decreasing order. We have just seen that this requires some efforts. We could do the following (in the
example, n=5=k):
> n := 5; k := 5;
n := 5
k := 5
> ListTools[Reverse]([seq(i,i=1..min(n,k))]);
[5, 4, 3, 2, 1]
Let’s see if we can put everything together. At first, the procedure part(n,k)
>
join := proc(n,a1) return map(proc(L,a1) return [a1,op(L)]; end, part(n-a1,a1),a1); end;
join := proc(na1) return map(proc(La1)
return [a1, op(L)] end proc; , part(n − a1, a1), a1)end proc;
> part := proc(n,k)
> if n = 0 then return [[]]; end;
> return
> map(proc(a1,n)
> op(join(n,a1))
> end,
> ListTools[Reverse]([seq(i,i=1..min(n,k))]),n);
> end;
return [[]] end if; ; return map(proc(a1n)
op(join(n, a1)) end proc; , ListTools[StringTools : −StringTools]([seq(i, i =
> part(0,0);
[[]]
>
part(1,1);
>
part(2,2);
[[1]]
[[2], [1, 1]]
>
part(3,3);
>
part(4,4);
[[3], [2, 1], [1, 1, 1]]
[[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]]
>
part(5,5);
[[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]]
108
Lab 9
Problem # 1
Create a list with the numbers n, n-2, n-4, n-6,...2 for any given even n
(i) using a for loop with appending to a list,
(ii) using the seq command,
(iii) using seq and map command using a function (i -> something),
(iv) using seq and map command using a procedure.
Problem # 2
(i) Create a function to compute the partitions of n into exactly k parts.
(ii) Create an 8 by 8 matrix whose (n, k)-th entry is the number of partitions of n with exactly k parts.
Problem # 3
Write code which takes as input a string and which reverses the order of the characters. i.e. “hallo” should
become “olla.”
Problem # 4
Solve the following equations with the solve command. Check your answers with a plot. In each case
substitute the roots into the expression on the left side of the equation to verify that the roots satisfy the
equation.
(a) x2 + 3x + 1 = 0
(b) x3 + x + 1.0 = 0
(c) x4 + 1 = 0
Problem # 5
Use plot and fsolve commands to find all solutions to the following equations over the given interval.
(a) sin2 (x) = cos(3x), 0 ≤ x ≤ π
(b) cos2 (x) = sin(3x), 0 ≤ x ≤ π
(c) 8 cos(x) = x, −∞ < x < ∞
Problem # 6
The general equation of a circle is x2 + y 2 + ax + by = c. Find the equation of the circle that passes through
three points (1, 1), (3, −1), and (6, 4).
109
2.9
Lecture 10: The Traveling Salesman Problem
In the Traveling Salesman Problem, one is given a network of places and mutual travel distances and tries
to find a route visiting every place once and returning to the origin in the end. The route is meant to be
short, where short is in terms of the given distances. The length of the route is simply the sum of all pairwise
distances along the route, including the return trip to the origin. Consider the following network of 10 cities:
A bad and a good route through the network are shown below:
110
Let us discuss a suitable data structure for a network. We think of the network as a list of places (cities) and
mutual distances (i.e., a graph). The places become “vertices” and the distances between any two places are
weights connected
to the edges connecting the respective vertices. That is, if n is the number of places, we
have e = n2 edges. To code this data structure in Maple, we decide to use a list of lists. The main list has
4 entries. The first two are the integers n and e describing the number of vertices and edges, respectively.
The next two entries are lists describing vertices and edges, respectively. The vertex list includes the name
of the place and the geographic location in terms of an x and y-coordinate pair. The edge list include the
numbers of the places they connect and the travel distance. The following Maple input is the network from
111
above, except that the edge list has been shortened for reasons of space.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
N := [10, 90,0,0];
N[3] := [[1,"Adelaide, SA",1,0,13800,-3400],
[2,"Bega NSW",1,0,14900,-3600],
[3,"Port Augusta SA",1,0,13700,-3200],
[4,"Eucla WA",1,0,12800,-3100],
[5,"Katherine NT",1,0,13200,-1400],
[6,"Brisbane QLD",1,0,15300,-2700],
[7,"Alice Springs, NT",1,0,13300,-2300],
[8,"Mt Gambier SA",1,0,14000,-3700],
[9,"Moree NSW",1,0,14900,-2900],
[10,"Townsville QLD",1,0,14600,-1900]];
N[4] := [[28,2,1,1329,0,0,0],
[861,3,1,305,0,0,0],
[300,4,1,1256,0,0,0],
[435,5,1,2709,0,0,0],
[66,6,1,2054,0,0,0],
[1313,10,8,2788,0,0,0],
[1312,10,9,1443,0,0,0]];
Here comes a routine to draw the network using the plot command.
>
>
>
>
>
>
>
>
>
>
network_plot_vertices := proc(N)
local P, L, i, n;
n := N[1];
L := [0$n];
for i to n do
L[i] := [N[3][i][5],N[3][i][6]];
end;
P := plot(L, style=point, symbol=circle);
return P;
end;
network plot vertices := proc(N )
local P, L, i, n;
n := N [1];
L := [0$n];
for i to n do
L[i] := [N [3][i][5], N [3][i][6]];
end do;
P := plot(L, style = point, symbol = circle);
return P ;
end proc;
>
network_plot_vertices(N);
112
Here comes a routine to plot a given tour. A tour is simply a permutation of n elements. We think of the
entries as the numbers of cities, the first one being the origin, the second one the second city on the trip,
then the third and so forth. The last entry which describes the n-th city on the tour is connected to the
origin.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
plot_tour := proc(N, T)
local P, L, i, j, n;
n := nops(T);
L := [0$n+1];
for i to n + 1 do
if i <= n then
j := T[i];
else
j := T[1];
end;
L[i] := [N[3][j][5],N[3][j][6]];
end;
P := plot(L, symbol=circle);
return P;
end;
113
plot tour := proc(N, T )
local P, L, i, j, n;
n := nops(T );
L := [0$n + 1];
for i to n + 1 do
if i ≤ n then
j := T [i];
else
j := T [1];
end if;
L[i] := [N [3][j][5], N [3][j][6]];
end do;
P := plot(L, symbol = circle);
return P
end proc;
The following function creates a random permutation of the n integers from 1 to n. It can be used to create
a random tour to begin with.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
random_permutation := proc(n)
local P,L, i, j, k, r, a;
L := [1$n];
P := [1$n];
for i to n do
L[i] := i;
end;
for i to n do
j := n - i + 1;
r := irem(rand(), j) + 1;
a := L[r];
P[i] := a;
for k from r + 1 to j do
L[k - 1] := L[k];
end;
end;
return P;
end;
114
random permutation := proc(n)
local P, L, i, j, k, r, a;
L := [1$n];
P := [1$n];
for i to n do
L[i] := i;
end do;
for i to n do
j := n − i + 1;
r := irem(rand (), j) + 1;
a := L[r];
P [i] := a;
for k from r + 1 to j do
L[k − 1] := L[k];
end do;
end do;
return P
end proc;
Let us create a random tour for the above network:
>
T := random_permutation(N[1]);
T := [2, 3, 10, 8, 1, 7, 4, 5, 6, 9]
We plot the tour:
>
plot_tour(N,T);
115
The tour isn’t that great in terms of the total distance traveled. Solving the TSP problem means finding
a short tour. We will do so by successively modifying the tour curently at hand in such a way that the
tours become better and better. This way, we hope to end up with a good solution. Since the problem is
NP-hard, a good solution is all we can hope for. In order to compute the best solution, exponentially many
tours would have to be compared (namely, n! many tours to be precise). This is computationally infeasible
in general.
We start be creating a function which computes the distance of two points on a cycle of length n.
>
>
>
>
>
>
>
>
>
>
>
>
>
cyclic_distance := proc(n, i, j)
local u, d1, d2;
if i > j then
return cyclic_distance(n, j, i);
end;
d1 := j - i;
d2 := n + i - j;
if d1 < d2 then
return d1;
else
return d2;
end;
end;
116
cyclic distance := proc(n, i, j)
local u, d1, d2;
if j < i then
return cyclic distance(n, j, i);
end if;
d1 := j − i;
d2 := n + i − j;
if d1 < d2 then
return d1;
else
return d2;
end if;
end proc;
>
cyclic_distance(6,1,4);
3
Next, we find a pair of vertices on a tour. The code is more complicated than necessary since it accommodates
for an additional condition on the cyclic distance of the pair of points. We, however, decide to not impose
any condition like that, except for the fact that the cyclic distance may not be zero, i.e., the points are not
equal.
> find_pair := proc(n)
> local i, j, d;
> i := irem(rand(), n) + 1;
> j := irem(rand(), n) + 1;
> d := cyclic_distance(n, i, j);
> while d <= 0 do
> i := irem(rand(), n) + 1;
> j := irem(rand(), n) + 1;
> d := cyclic_distance(n, i, j);
> end;
> return [i,j];
> end;
find pair := proc(n)
local i, j, d;
i := irem(rand (), n) + 1;
j := irem(rand (), n) + 1;
d := cyclic distance(n, i, j);
while d ≤ 0 do
i := irem(rand (), n) + 1;
j := irem(rand (), n) + 1;
d := cyclic distance(n, i, j);
end do;
return [i, j];
end proc;
117
Here comes a function to increment an index in a cycle of length n.
> inc_mod := proc(n, i)
> return irem(i,n) + 1;
> end;
inc mod := proc(n, i)
return irem(i, n) + 1;
end proc;
>
inc_mod(5,5);
1
Another function to decrement an index modulo n.
> dec_mod := proc(n, i)
> if i = 1 then return n; end;
> return i - 1;
> end;
dec mod := proc(n, i)
if i = 1 then
return n;
end if;
return i − 1;
end proc;
>
dec_mod(5,5);
4
The next function computes the tour obtained from a given tour T by doing a 2-swap. For a pair of indeices
i and j, the vertices on the tour in positions i + 1, i + 2, . . . , j are reversed in order.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
swap_tour := proc(T, i, j)
local S, u, v, k, n;
n := nops(T);
S := [0$n];
for k to n do
S[k] := T[k];
end;
u := inc_mod(n, i);
S[u] := T[j];
S[j] := T[u];
u := inc_mod(n, u);
v := dec_mod(n, j);
while u <> j do
S[u] := T[v];
u := inc_mod(n, u);
v := dec_mod(n, v);
end;
return S;
end;
118
swap tour := proc(T, i, j)
local S, u, v, k, n;
n := nops(T );
S := [0$n];
for k to n do
S[k] := T [k];
end do;
u := inc mod (n, i);
S[u] := T [j];
S[j] := T [u];
u := inc mod (n, u);
v := dec mod (n, j);
while u <> j do
S[u] := T [v];
u := inc mod (n, u);
v := dec mod (n, v);
end do;
return S;
end proc;
The next function, new tour, combines finding a pair of indices (i, j) and doing a 2-swap.
>
>
>
>
>
>
>
>
new_tour := proc(T)
local n, ij, i, j;
n := nops(T);
ij := find_pair(n);
i := ij[1];
j := ij[2];
return swap_tour(T,i,j);
end;
new tour := proc(T )
local n, ij, i, j;
n := nops(T );
ij := find pair (n);
i := ij[1];
j := ij[2];
return swap tour (T, i, j);
end proc;
Consider an example. We create a random tour:
>
T := random_permutation(10);
T := [10, 8, 2, 4, 5, 9, 3, 7, 1, 6]
119
Using new tour, we create a variation S of T. The new tour S is obtained from T by a 2-swap for the pair
(i, j) = (8, 6). That is, the interval 9, 10, 1, 2, 3, 4, 5, 6 is reversed, i.e.,
S[9] = T [6] = 9, S[10] = T [5] = 5, S[1] = T [4] = 4, S[2] = T [3] = 2,
S[3] = T [2] = 8, S[4] = T [1] = 10, S[5] = T [10] = 6, S[6] = T [9] = 1.
>
S := new_tour(T);
S := [4, 2, 8, 10, 6, 1, 3, 7, 9, 5]
Next we need a function which finds an edge in the network data structure. Given two city indices, we need
the position of the edge between the two cities in the edge list. There are much better ways to do it than
what we do here, sine we employ a simple linear search through the list of edges.
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
find_edge := proc(N, a, b)
local n, i, c, d;
n := N[2];
for i to n do
c := N[4][i][2];
d := N[4][i][3];
if a = c and b = d then
return i;
end;
if a = d and b = c then
return i;
end;
end;
return -1;
end;
find edge := proc(N, a, b)
local n, i, c, d;
n := N [2];
for i to n do
c := N [4][i][2];
d := N [4][i][3];
if a = c and b = d then
return i;
end if;
if a = d and b = c then
return i;
end if;
end do;
return − 1;
end proc;
120
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
cost := proc(N, T)
local i, j, a, b, n, c, C;
C := 0;
n := N[1];
for i to n do
a := T[i];
if i < n then
b := T[i + 1];
else
b := T[1];
end;
j := find_edge(N, a, b);
if j >= 1 then
c := N[4][j][4];
else
c := 10000;
end;
C := C + c;
end;
return C;
end;
And now the cost function. Given a tour, we add up the costs along the edges between succesive cities along
the tour. We include the cost of the edge between the last city and the firt city on the tour.
cost := proc(N, T )
local i, j, a, b, n, c, C;
C := 0;
n := N [1];
for i to n do
a := T [i];
if i < n then
b := T [i + 1];
else
b := T [1];
end if;
j := find edge(N, a, b);
if 1 ≤ j then
c := N [4][j][4];
else
c := 10000;
end if;
C := C + c;
end do;
return C;
end proc;
121
We can now compute the cost of a given tour:
> cost(N,T);
20309
>
cost(N,S);
20309
And now the main routine TSP, which tries to find a good tour. It does so by trying to improve the tour
at hand. Actually, the procedure never stops. You have to interrup the computation using the little red
button in order to stop. The TSP function prints out a tour when it found one that improves upon what he
currently has. This way, using copy and paste, you can obtain the best known tour and manually store it in
a variable.
> TSP := proc(N,T0)
> local S,T,n,C,c;
> n := N[1];
> #T := random_permutation(n);
> T := T0;
> C := cost(N,T);
> print(C,T);
> while true do
> S := new_tour(T);
> c := cost(N,S);
> #print(c);
> if c < C then
> T := S;
> C := c;
> print(C,T);
> #print("improvement");
> end;
> end;
> end;
TSP := proc(N, T 0)
local S, T, n, C, c;
n := N [1];
T := T 0;
C := cost(N, T );
print(C, T );
do
S := new tour (T );
c := cost(N, S);
if c < C then
T := S;
C := c;
print(C, T );
end if;
end do;
end proc;
Consider an example. Start with a random tour.
122
>
T := random_permutation(N[1]);
T := [1, 2, 10, 3, 8, 7, 5, 9, 6, 4]
Plot the tour.
>
plot_tour(N,T);
Compute its cost.
>
cost(N,T);
17854
Plot the tour again, this time with little circles around the vertices.
>
D1 := plot_tour(N,T):
>
D2 := network_plot_vertices(N):
>
with(plottools):with(plots):
\begin{Maple Warning}{\normalsize{Warning, the previous binding of the name arrow has been removed and it now ha
>
display(D1,D2);
123
Call TSP to improve on the tour. For sake of space, we have deleted some of the output.
>
TSP(N,T);
17854,
17244,
17099,
16120,
15684,
14946,
13045,
12261,
[1, 2, 10, 3, 8, 7, 5, 9, 6, 4]
[3, 10, 2, 1, 8, 7, 5, 9, 6, 4]
[6, 10, 2, 1, 8, 7, 5, 9, 3, 4]
[4, 3, 2, 1, 8, 7, 5, 9, 10, 6]
[5, 7, 8, 1, 2, 3, 4, 9, 10, 6]
[3, 2, 8, 1, 7, 5, 6, 10, 9, 4]
[1, 8, 2, 3, 4, 9, 6, 10, 5, 7]
[1, 8, 4, 3, 2, 9, 6, 10, 5, 7]
11684, [2, 8, 4, 3, 1, 7, 5, 10, 6, 9]
11074, [5, 7, 4, 3, 1, 8, 2, 9, 6, 10]
\begin{Maple Warning}{\normalsize{Warning,
computation interrupted}}\end{Maple Warning}
The computation has been interrupted after it appeared that the last tour could not be improved. We
copy-paste the last tour into T.
>
T := [5, 7, 4, 3, 1, 8, 2, 9, 6, 10];
T := [5, 7, 4, 3, 1, 8, 2, 9, 6, 10]
We plot what we believe is a local optimal tour. It might even be the best possible tour. But we have not
proved that. It would require examining the 10!/10 = 9! possible tours.
>
D1 := plot_tour(N,T):D2 := network_plot_vertices(N):display(D1,D2);
124
And now, for the fun of it, a real big example. This one has 55 cities. For sake of space, the input is
truncated.
> N := [55, 1485,0,0];
> N[3] := [[1,"Adelaide, SA",1,0,13800,-3400],
> [2,"Albany, WA",1,0,11700,-3400],
> [3,"Albury, NSW",1,0,14600,-3600],
> [4,"Alice Springs, NT",1,0,13300,-2300],
> [5,"Ayers Rock/Yulara NT",1,0,13100,-2500],
> [6,"Bairnsdale VIC",1,0,14700,-3700],
> [7,"Ballarat VIC",1,0,14300,-3700],
> [8,"Bathurst NSW",1,0,14900,-3300],
> [9,"Bega NSW",1,0,14900,-3600],
> [51,"Toowoomba QLD",1,0,15100,-2700],
> [52,"Townsville QLD",1,0,14600,-1900],
> [53,"Wagga Wagga NSW",1,0,14700,-3500],
> [54,"Warrnambool VIC",1,0,14200,-3800],
> [55,"West Wyalong NSW",1,0,14700,-3300]];
> N[4] := [[0,2,1,2642,0,0,0],
> [1,3,1,932,0,0,0],
> [2,3,2,3570,0,0,0],
> [3,4,1,1526,0,0,0],
> [4,4,2,3558,0,0,0],
> [5,4,3,2458,0,0,0],
> [1483,55,53,153,0,0,0],
> [1484,55,54,661,0,0,0]];
Start with a random tour.
>
T := random_permutation(N[1]);
125
Call TSP to improve on the random tour.
>
TSP(N,T);
\begin{Maple Warning}{\normalsize{Warning,
computation interrupted}}\end{Maple Warning}
The computation has been interrupted.
T := [48, 55, 10, 7, 36, 54, 39, 29, 37, 46, 14, 43, 2, 25, 15, 44, 35, 30, 26, 16, 42,
19, 32, 31, 23, 20, 27, 45, 53, 18, 9, 3, 6, 1, 11, 22, 5, 50, 4, 17, 34, 47, 49, 24, 38,
8, 12, 51, 28, 33, 52, 40, 21, 13, 41];
>
Plot the tour:
>
D1 := plot_tour(N,T):D2 := network_plot_vertices(N):display(D1,D2);
Call TSP again.
>
TSP(N,T);
\begin{Maple Warning}{\normalsize{Warning,
computation interrupted}}\end{Maple Warning}
126
The computation has been interrupted.
T := [23, 45, 22, 5, 50, 4, 46, 37, 53, 55, 14, 12, 47, 34, 52, 17, 40, 33, 21, 38, 13,
28, 51, 49, 24, 8, 41, 48, 18, 9, 3, 6, 10, 7, 36, 54, 39, 29, 11, 1, 43, 20, 26, 30, 2,
25, 15, 44, 35, 27, 16, 42, 19, 32, 31];
>
Plot the tour:
>
D1 := plot_tour(N,T):D2 := network_plot_vertices(N):display(D1,D2);
Call TSP again.
>
TSP(N,T);
\begin{Maple Warning}{\normalsize{Warning,
computation interrupted}}\end{Maple Warning}
The computation has been interrupted.
T := [4, 5, 22, 46, 37, 53, 55, 24, 14, 12, 21, 33, 40, 17, 52, 34, 47, 51, 13, 28,
38, 49, 8, 41, 48, 18, 9, 6, 3, 10, 36, 7, 54, 39, 29, 11, 1, 43, 45, 20, 26, 30, 25, 2,
16, 42, 27, 19, 35, 44, 15, 32, 31, 23, 50];
>
Plot the tour:
>
D1 := plot_tour(N,T):D2 := network_plot_vertices(N):display(D1,D2);
127
128
2.10
>
Lecture 11: Mandelbrot Sets
with(plots):
\begin{Maple Warning}{\normalsize{Warning, the name changecoords has been redefined}}\end{Maple Warning}
>
with(plottools):
\begin{Maple Warning}{\normalsize{Warning, the assigned name arrow now has a global binding}}\end{Maple Warning}
Complex Numbers a complex number is of the form x + yi where i = sqrt(-1). x is called the Real part, y
is the Imaginary part Maple uses I for sqrt(-1) (to allow the use of i in for loops, for example). addition is
componentwise, i.e. (x +y*I) + (u + v*I) = (x+u) + (y+v)*I multiplication is done using the relation Iˆ2
= -1: (x + y*I) * (u + v*I) = (x*u - y*u) + (x*v + y*u)*I i.e.
>
c1 := 1 + 2*I;
c1 := 1 + 2 i
>
c2 = 2 + 3*I;
c2 = 2 + 3 i
>
c1 + c2;
1 + 2 i + c2
>
c1 * c2;
(1 + 2 i) c2
inversion is a little more complicated: we have 1/(x+y*I) = x/(xˆ2+yˆ2) - y/(xˆ2+yˆ2)*I, i.e.,
>
1/c1;
1/5 − 2/5 i
One may think of the complex numbers as spead out in a plane, with the Real and Imaginary parts corresponding to the x and the y coordinates, respectively. The absolute value of c=(x + y*I) is defined as
sqrt(xˆ2 + yˆ2). It is the ”distance from the origin”. Complex numbers sometimes show chaotic behavior.
For example, for a given z0 = x + y*I, iteration of the function z -> zˆ2 + z0 may or may not result in
arbitrarily large absolute values of z.
>
>
mandelbrotSet := proc(x,y)
local z, m;
z := evalf( x + y*I );
m := 0;
to 10 while abs(z) < 2 do
z := z^2 + (x+y*I);
m := m + 1;
end;
return m;
end:
>
mandelbrotSet(0.1,0.1);
>
>
>
>
>
>
>
>
10
>
plot3d(mandelbrotSet, -3/2..3/2,-3/2..3/2, grid=[50,50]);
129
plot3d(0, -2 .. 0.7, -1.1 .. 1.1, orientation=[-90,0], grid=[250, 250],
style=patchnogrid, scaling=constrained, color=mandelbrotSet);
>
We can make it faster and nicer:http://www.math.utsa.edu/mirrors/maple/mfrmandf.htm
130
>
restart:
with(plots):
\begin{Maple Warning}{\normalsize{Warning, the name changecoords has been redefined}}\end{Maple Warning}
mandelbrot_fast:=proc(x, y)
local xn, xnold, yn, m;
Digits:=10; # optional
xn:=x;
yn:=y;
for m from 0 to 25 while evalhf(sqrt(xn^2+yn^2)) < 2 do
xnold:=xn;
xn:=evalhf(xn^2-yn^2+x);
yn:=evalhf(2*xnold*yn+y)
od;
m;
end:
> plot3d(0, -2 ..
0.7, -1.1 .. 1.1, orientation=[-90,0], grid=[250, 250],
style=patchnogrid, scaling=constrained, color=mandelbrot_fast);
>
131
2.11
Lecture 12: Elliptic Curves
Warning: The topic of this section requires more advanced mathematics, like the concept of finite fields and
some understanding of the projective plane.
>
f(x) := x * (x-1) * (x+1);
f (x) := x (x − 1) (x + 1)
>
plot(f(x),x=-2..2);
>
plot(sqrt(f(x)),x=-2..2);
132
>
plot([sqrt(f(x)),-sqrt(f(x))],x=-2..2);
>
g(x) := x^3 + 73;
g (x) := x3 + 73
133
>
plot(g(x),x=-5..5);
>
plot([sqrt(g(x)),-sqrt(g(x))],x=-5..5);
134
>
C := plot([sqrt(g(x)),-sqrt(g(x))],x=-5..5):
>
with(plottools):
>
with(plots):
\begin{Maple Warning}{\normalsize{Warning, the name changecoords has been redefined}}\end{Maple Warning}
\begin{Maple Warning}{\normalsize{Warning, the previous binding of the name arrow has been removed and it now ha
>
display(C);
There is a special command for plotting curves, implicitplot
>
implicitplot(y^2-x^3-73,x=-5..5,y=-12..12);
135
>
C := implicitplot(y^2-x^3-73,x=-5..5,y=-12..12):
x=3 gives y=9 (and y=-9), i.e. we have found an integral point on the curve (an integral point is simply a
point whose coordinates are integers)
>
P1 := pointplot([2,9]);
P1 := INTERFACE PLOT (POINTS ([2.0, 9.0]))
>
display(C,P1);
136
BTW, such a curve is called elliptic curve. x=3 gives y=10 (and -10), ie we have found another integral
point on the curve
>
P2 := pointplot([3,10]);
P2 := INTERFACE PLOT (POINTS ([3.0, 10.0]))
>
display(C,P1,P2);
137
Let’s determine the line through the two points. Its equation is y = x+7. Check: plugging in 2 gives 9,
plugging in 3 gives 10.
>
L := plot(x+7,x=-5..5):
>
display(C,P1,P2,L);
138
The line L intersects the curve in another point.
>
solve(sqrt(g(x))-(x+7),x);
3, 2, −4
OK, the third point is at x=-4
>
simplify(eval(sqrt(g(x)),x=-4));
3
That was a bit complicated, but anyway. The thrid integral point is P3 = (-4,3)
>
P3 := pointplot([-4,3]);
P3 := INTERFACE PLOT (POINTS ([−4.0, 3.0]))
>
display(C,L,P1,P2,P3);
139
the main point was that knowing two (integral) points on the curve enabled us to produce another (integral)
point. Now comes a nice trick from algebraic geometry: we substitute x=X/Z and y = Y/Z into the equation
of the curve to get Yˆ2/Zˆ2 = Xˆ3/Zˆ3 + 73 and hence Yˆ2Z = Xˆ3 + 73Zˆ3 this is an equation of a curve
in 3 variables. The equation is homogeneous of degree 3. This means that whenever (X,Y,Z) is a solution,
then also any non-zero scalar multiple (aX,aY,aZ) is a solution. In particular, we find that the points (x,y,1)
are solutions, provided (x,y) was a solution to the original equation. In addition, there is the solution (0,1,0).
We may think of the scalar multiples of (X,Y,Z) as being an entity, called a projective point. To express
the fact that we consider scalar multiples, we write (X:Y:Z). The new points (X:Y:1) behave much like the
old points, more precisely, they are in 1-1 correspondence. In addition, the curve has the new point (0:1:0),
which we may imagine as sitting on top of the Y-axis. (and also at the very bottom of the Y-axis). We have
just introduced the projective plane over the reals. It looks much like the ordinary (affine) plane except that
it has points (X:Y:0) which we may imagine as sitting far out. We say that these are the points at infinity.
So, projectively, the elliptic curve has one more point than it has in the affine plane.
Let’s look at what happens to lines. The vertical lines of the form x=c, c a constant, become X/Z=c or
X=cZ. Thus, the point at infinity (i.e. Z=0) (0:1:0) is on all these vertical lines. Lines of the form y = mx +
c become Y/Z = mX/Z + c or Y = mX + cZ. The point at infinity (1:m:0) is on all those lines for fixed m,
i.e. for fixed slope. That is, the parallel lines of the form y = mx + b for fixed m and various b all intersect
in the point (1:m:0). The vertical lines all intersect in (0:1:0). Sadly enough, there is no Maple command
to plot curves in the projective plane. As a curiosity, the line Z=0 is a line which contains all the points at
infinity. This line contains no affine point, and hence cannot be seen in the affine x/y-plane.
From now on, let us identify (x,y) with (x:y:1). Also, it is usual to denote (0:1:0) as infinity. The main idea
is to introduce a group structure on the points of an elliptic curve as follows: infinity is the identity element
in the group. For points P,Q,R we say that P + Q + R = infinity (=0) if and only if P,Q,R are collinear
>
display(C,L,P1,P2,P3);
140
This is just saying that P1+P2+P3 = 0.
It is a nice fact that in the projective plane, a line intersects the elliptic curve in exactly three points,
provided one counts points with the appropriate multiplicities, i.e. a tangent point counts twice. In other
words, three points add to infinity (ie zero in the group) if they are collinear (collinear = being on a line).
Since the vertical lines intersect at infinity, we automatically have that if P=(x,y) then -P=(x,-y) since
(x,y),(x,-y),infinity are collinear.
>
P3 := pointplot([-4,3]);
P3 := INTERFACE PLOT (POINTS ([−4.0, 3.0]))
>
P3minus := pointplot([-4,-3]);
P3minus := INTERFACE PLOT (POINTS ([−4.0, −3.0]))
>
L3 := implicitplot(x+4,x=-5..5,y=-12..12):
>
display(C,P3,P3minus,L3);
141
Thus, to add points P and Q, one rewrites the fundamental equation P+Q+R=infinity as P+Q=-R. Thus,
to compute P+Q one has to take the line through P and Q, intersect it with the curve to get R = (x,y).
Then P+Q = -R = (x,-y). Thus, P1+P2=-P3, i.e.
>
display(C,P1,P2,P3minus,L,L3);
142
The crucial point is that the resulting addition is associative, i.e. P+(Q+R) = (P+Q)+R. Showing this is
non-trivial.
It is possible to write down general formulas for the addition of points on the curve. To add a point P to
itself, one draws the tangent line to the curve at that point and intersects it with the curve. Negation of the
y-coordinate gives 2P.
Example: let’s add P3 to itself.
the slope of the tanget of C at P3 is obtained by implicitly differentiating the equation for C. So yˆ2=xˆ3+73
differentiated implicitly gives 2y dy = 3xˆ2 dx, i.e. dy/dx = 3/2 xˆ2/y. Plugging in the coordinates of P3=(4,-3) gives dy/dx at P3 = 3/2 * 16/(-3) = -8. The equation of the langent line is therefore -8 * (x+4) -3
>
T := plot(-8 * (x+4) -3,x=-5..5,y=-12..12):
>
display(C,T,P3);
143
Let us find the ”third” intersection point. note that we have to take the negative branch
>
solve(-sqrt(g(x))-((-8)*(x+4)-3),x);
−4, 72
So, the third point is at (72,?)
>
simplify(eval(-sqrt(g(x)),x=72));
−611
OK the point is (72,-611)
>
P4 := pointplot([72,-611]);
P4 := INTERFACE PLOT (POINTS ([72.0, −611.0]))
>
display([C,P3,P4,T]);
144
>
>
>
T := plot(-8 * (x+4) -3,x=-20..75,y=-650..650):
C := plot([sqrt(g(x)),-sqrt(g(x))],x=-20..75,y=-650..650):
display(C,T,P4);
145
>
P4negative := pointplot([72,611]);
>
P4negative := INTERFACE PLOT (POINTS ([72.0, 611.0]))
display(C,T,P3,P4negative);
thus we have computed 2*P3
In general, if the curve E is given by yˆ2=xˆ3+bx+c and if P1 = (x1,y1), P2=(x2,y2) then P3 = (x3,y3) where
x3 = mˆ2 - x1-x2 y3 = m(x1-x3)-y1 and m= (y2-y1)/(x2-x1) if P1 not equal P2 and m = (3*x1ˆ2+b)/(2*y1)
if P1 = P2. If the slope m is infinite then P3 = infinity Also, infinity + P = P for all points P. This addition
is associative, infinity is the identity element, and the inverse of P=(x,y) is -P=(x,-y). Thus we have a group.
The group is abelian, as P+Q = Q+P (as can be seen from the fact that the formulae are symmetric in x
and y (up to a minus sign which cancels). Thus we have an abelian group.
146
2.12
Lecture 13: A Sudoku Puzzle Solver
The following Maple code provides a sudoku solver. The sudoku in the example is taken from the web site
websudoku.com. It is easy sudoku no. 8,286,509,821, retrieved on 6/8/2007. The Sudoku solver tries all
possible completions. It prints all completions that are possible. In general, there is only one. The code is
listed as fomatted by maple, rather than the way it was typed in. This is to allow for indentation to make
the code look somewhat nicer.
ispossible := proc(M, i, j, d)
local u, v, x, y;
if M [i, j] <> 0 then
return f alse
end if; ;
for v to 9 do
if M [i, v] = d then
return f alse
end if;
end do; ;
for u to 9 do
if M [u, j] = d then
return f alse
end if;
end do; ;
x := i − irem(i − 1, 3);
y := j − irem(j − 1, 3);
for u to 3 do
for v to 3 do
if M [xu − 1, yv − 1] = d then
return f alse
end if;
end do;
end do; ;
return true
end proc;
147
compute possibilities := proc(M )
local P, i, j, d;
P := Matrix (9, 9);
for i to 9 do
for j to 9 do
P [i, j] := [];
for d to 9 do
if ispossible(M, i, j, d) then
P [i, j] := [op(P [i, j]), d]
end if;
end do;
end do;
end do; ;
return P
end proc;
find tight spot := proc(M, P )
local i, j, u, v, nb, nb0;
u := 0;
v := 0;
nb0 := 10;
for i to 9 do
for j to 9 do
if M [i, j] = 0 then
nb := nops(P [i, j]);
if nb < nb0 then
u := i;
v := j;
nb0 := nb
end if;
end if;
end do;
end do; ;
return [u, v]
end proc;
148
sudoku := proc(M )
local P, uv, u, v, n, i, d;
P := compute possibilities(M );
uv := find tight spot(M, P );
if uv[1] = 0 then
print(M )
else
u := uv[1];
v := uv[2];
n := nops(P [u, v]);
for i to n do
d := P [u, v][i];
M [u, v] := d;
sudoku(M );
M [u, v] := 0
end do;
end if;
end proc;
>
M := Matrix(9,9,[[5,9,8,0,0,4,1,0,0],[0,1,0,0,0,7,0,0,5],[0,4,7,0,0,0,0,6,9],[8,6,0,0,7,0,5,0,0],[


5 9 8 0 0 4 1 0 0


 0 1 0 0 0 7 0 0 5 




 0 4 7 0 0 0 0 6 9 




 8 6 0 0 7 0 5 0 0 





M :=  0 2 0 3 0 5 0 9 0 



 0 0 5 0 2 0 0 7 1 




 3 5 0 0 0 0 2 1 0 




 4 0 0 1 0 0 0 5 0 


0 0 2 4 0 0 9 8 6
>
sudoku(M);
149


5
9
8
6
3
4
1
2
7





















6
1
3
2
9
7
8
4
2
4
7
5
1
8
3
6
8
6
4
9
7
1
5
3
7
2
1
3
4
5
6
9
9
3
5
8
2
6
4
7
3
5
6
7
8
9
2
1
4
8
9
1
6
2
7
5

5 


9 


2 


8 


1 


4 


3 

1
7
2
4
5
3
9
8
150
6
2.13
Lecture 14: The Complex Function 1 over z
>
>
with(plots):
complexGraph := proc(f, g, a, b, h)
local l,l2,i,j,p1,p2;
l := [];
for i from a to b by h do
for j from a to b by h do
if g(i+j*I) then
l:=[op(l),i+j*I];
fi;
od;
od;
print(l);
l2 := map(f,l);
p1 := complexplot(l,x=a..b,style=point,color=blue):
p2 := complexplot(l2,x=a..b,style=point,color=red):
printf(‘The domain is in blue, the co-domain is in red.
display(p1,p2,view=[a..b,a..b]);
end:
>
f:=z->1/z;
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
\n’);
f := z 7→ z −1
>
g:=z->evalf(abs(z))<1;
g := z 7→ |z| < 1
>
complexGraph(f,g,-2,2,.05);
+ 0.55 i, −0.75 − 0.65 i, −0.75 − 0.60 i, −0.75 − 0.55 i, −0.75 − 0.50 i, −0.75 − 0.45 i, −0.75 − 0.40 i, −0.75 − 0.35 i, −0.75 − 0.30 i, −0.75 − 0.25 i
151
2.14
Lecture 15: Calculus
2.15
Calculus Lab 1
Problem # 1
- Assign the variable name
√ a to the number 2π/5 and then use evalf to compute the decimal approximations for a2 , 1/a, a, a1.3 , sin(a), and tan(a). Don’t forget to assign a variable to each of these
values.
- The number of significant digit can be changed from the default value of 10 to some other number,
such as 20, with the command Digits:=20;. Repeat the previous exercise with 20 significant digits.
Problem # 2
- Expand the following expressions.
(a) (x2 + 2x − 1)3 (x2 − 2)
(b) sin(x − 2y) cos(2x − y)
- Factor the expression x2 + 3x + 2. What happens if this expression is changed to x2 + 3.0x + 2.0?
- Simplify
2x2
3x
+
x3 − 1 x2 − 1
Problem # 3
2
−2x+1
- Plot the graph of y = 3x x−1
over a small interval containing x = 1, for example 0 ≤ x ≤ 2.
Experiment with the y-range to obtain a reasonable plot. What happens to the graph near x = 1?
- Now plot the same expression over a large interval such as −100 ≤ x ≤ 100. Note that the behavior of
the graph near x = 1 is no longer apparent. Why do you think this happens?
Problem # 4
Label the points P0 := [1, 2] and P1 := [3, 7] on the same input line. Load the student package by typing
with(student);. Find out the syntax for determining the slope between the two points using the command
?slope. Find the slope between P0 and P1 . Assign the value that you find to the variable m.
152
Solutions
>
with(student):
PROBLEM 1
> a:=2*Pi/5;
a := 2/5 π
>
a2:=evalf(a^2);
a2 := 1.5791367041742973791
>
a3:=evalf(1/a);
a3 := 0.79577471545947667882
>
a4:=evalf(sqrt(a));
>
a4:=evalf(a^(1.3));
a4 := 1.1209982432795857399
a4 := 1.3457761370185493772
>
a5:=evalf(sin(a));
a5 := 0.95105651629515357212
>
a5:=evalf(tan(a));
a5 := 3.0776835371752534027
>
Digits:=20;
>
a2:=evalf(a^2);
>
a3:=evalf(1/a);
a2 := 1.5791367041742973791
a3 := 0.79577471545947667882
>
a4:=evalf(sqrt(a));
>
a4:=evalf(a^(1.3));
>
a5:=evalf(sin(a));
a4 := 1.1209982432795857399
a4 := 1.3457761370185493772
a5 := 0.95105651629515357212
>
a5:=evalf(tan(a));
a5 := 3.0776835371752534027
PROBLEM 2
> f:=(x^2+2*x-1)^3*(x^2-2);
3 2
f := x2 + 2 x − 1
x −2
>
expand(f);
>
x8 + 7 x6 + 6 x7 − 16 x5 − 27 x4 + 14 x3 + 17 x2 − 12 x + 2
g:=sin(x-2*y)*cos(2*x-y);
>
expand(g);
g := sin (x − 2 y) cos (2 x − y)
2
2
2
2
3
2
in (x)) (cos (y)) sin (y) cos (x) − 2 sin (x) cos (y) (cos (x)) + sin (x) cos (y) − 2 sin (y) (sin (x)) cos (x) − 4 (cos (x)) sin (y) (cos (y)) + 2 cos (x
> simplify(%);
2
3
2
3
2
2
x)) − 2 sin (x) (cos (y)) + 6 cos (x) sin (y) (cos (y)) − 8 (cos (x)) sin (y) (cos (y)) − 6 sin (x) cos (y) (cos (x)) + sin (x) cos (y) − 2 cos (x) sin (
> f:=x^2+3*x+2;
153
f := x2 + 3 x + 2
>
factor(f);
(x + 2) (x + 1)
>
f:=x^2+3.0*x+2.0;
f := x2 + 3.0 x + 2.0
>
factor(f);
(x + 2.0) (x + 1.0)
>
f:=2*x^2/(x^3-1)+3*x/(x^2-1);
2
f := 2 x3x−1 + 3 x2x−1
>
simplify(f);
(5 x2 +5 x+3)x
(x2 −1)(x2 +x+1)
PROBLEM 3
>
f:=(3*x^2-2*x+1)/(x-1);
f :=
>
plot(f,x=0..2,y=-10..10);
>
plot(f,x=-100..100,y=-10..10);
3 x2 −2 x+1
x−1
154
PROBLEM 4
> P0:=[1,2]; P1:=[3,7];
P0 := [1, 2]
P1 := [3, 7]
>
m:=slope(P0,P1);
m := 5/2
155
2.16
Calculus Lab 2
Problem # 1
- Enter an expression that describes the area of a square in terms of its diagonal length. Use the variable
name sqarea for the area of the square and let d be the diagonal length. Use the subs command to
compute the area of the square when d = 2 and d = 3.7.
- Enter an expression that describes the area of a circle in terms of its circumference. Use the variable
name clarea for the area of the circle and let p be the circumference. Use the subs command to
compute the area of the circle when p = 2 and p = 3.7.
Problem # 2
Solve the following equations with the solve command. Check your answers with a plot. In each case
substitute the roots into the expression on the left side of the equation to verify that the roots satisfy the
equation.
(a) x2 + 3x + 1 = 0
(b) x3 + x + 1.0 = 0
(c) x4 + 1 = 0
Problem # 3
Use plot and fsolve commands to find all solutions to the following equations over the given interval.
(a) sin2 (x) = cos(3x), 0 ≤ x ≤ π
(b) cos2 (x) = sin(3x), 0 ≤ x ≤ π
(c) 8 cos(x) = x, −∞ < x < ∞
Problem # 4
- Use the plot3d command to view the graphs of the following expressions:
(a) f := x2 − y 2
(b) f := (x2 − y 2 )(x + y)
(c) f := cos(x + y)
- For each of the following, plot the pair of expressions over the given intervals using display.
(a) f := x4 − 2x2 , −2 ≤ x ≤ 2, and g := x3 − x − 1, −1 ≤ x ≤ 3
(b) f := sin(x) + cos(x), −2π ≤ x ≤ 0, and g :=
tan(x)
tan(x)+1 ,
0 ≤ x ≤ π/2
Problem # 5
The general equation of a circle is x2 + y 2 + ax + by = c. Find the equation of the circle that passes through
three points (1, 1), (3, −1), and (6, 4).
156
Solutions
Problem 1:
> sqarea:=0.5*d^2;
>
sqarea := 0.5 d2
subs(d=2,sqarea); subs(d=3.7,sqarea);
2.0
6.845
clarea:=p^2/4/Pi;
>
clarea := 1/4 pπ
subs(p=2,clarea); evalf(%); subs(p=3.7,clarea); evalf(%);
>
2
π −1
0.3183098861
3.422500000 π −1
1.089415585
Problem 2:
> f:=x^2+3*x+1;
f := x2 + 3 x + 1
>
>
>
>
r:=solve(f=0,x);
√
√
r := −3/2 + 1/2 5, −3/2 − 1/2 5
simplify(subs(x=r[1],f));
0
simplify(subs(x=r[2],f));
0
f:=x^3+x+1.0;
f := x3 + x + 1.0
>
>
>
>
r:=solve(f=0,x);
r := −0.6823278038, 0.3411639019 − 1.161541400 i, 0.3411639019 + 1.161541400 i
subs(x=r[1],f);
0.0000000001
subs(x=r[2],f);
−0.0000000001 + 0.0 i
f:=x^4+1;
f := x4 + 1
>
>
>
>
>
r:=solve(f=0,x);
√
√
√
√
√
√
√
√
r := 1/2 2 + 1/2 i 2, −1/2 2 + 1/2 i 2, −1/2 2 − 1/2 i 2, 1/2 2 − 1/2 i 2
simplify(subs(x=r[1],f));
0
simplify(subs(x=r[2],f));
0
simplify(subs(x=r[3],f));
0
simplify(subs(x=r[4],f));
0
157
Problem 3:
>
f:=(sin(x))^2; g:=cos(3*x);
2
f := (sin (x))
g := cos (3 x)
>
plot(f,g,x=0..Pi);
>
d[1]:=fsolve(f=g,x=0..0.5);
d1 := 0.4580073241
>
d[2]:=fsolve(f=g,x=1.5..2);
d2 := 1.927889072
>
d[3]:=fsolve(f=g,x=2.1..3);
d3 := 2.493743311
>
f:=(cos(x))^2; g:=sin(3*x);
2
f := (cos (x))
g := sin (3 x)
>
plot(f,g,x=0..Pi);
158
>
d[1]:=fsolve(f=g,x=0..0.5);
d1 := 0.3570927449
>
d[2]:=fsolve(f=g,x=0.5..1);
d2 := 0.9229469842
>
d[3]:=fsolve(f=g,x=2..2.5);
d3 := 2.218645669
>
d[4]:=fsolve(f=g,x=2.5..3);
d4 := 2.784499909
>
f:=8*cos(x); g:=x;
f := 8 cos (x)
g := x
>
plot(f,g,x=-5..8);
159
>
d[1]:=fsolve(f=g,x=-5..-4);
d1 := −4.164830914
>
d[2]:=fsolve(f=g,x=-2..0);
d2 := −1.797406680
>
d[3]:=fsolve(f=g,x=0..2);
d3 := 1.395466144
>
d[4]:=fsolve(f=g,x=4..6);
d4 := 5.464302831
>
d[5]:=fsolve(f=g,x=6..8);
d5 := 6.830674326
Problem 4:
>
f:=x^2-y^2;
f := x2 − y 2
>
plot3d(f,x=-2..2,y=-2..2);
160
>
f:=(x^2-y^2)*(x+y);
f := x2 − y 2 (x + y)
>
plot3d(f,x=-2..2,y=-2..2);
161
>
f:=cos(x+y);
f := cos (x + y)
>
plot3d(f,x=-Pi..Pi,y=-Pi..Pi);
>
with(plots):
f:=x^4-2*x^2; g:=x^3-x-1; p1:=plot(f,x=-2..2):p2:=plot(g,x=-1..3):display([p1,p2]);
f := x4 − 2 x2
g := x3 − x − 1
162
with(plots): f := sin(x)+cos(x): g:= tan(x)/(tan(x)+1):
p2:=plot(g,x=0..Pi/2):display([p1,p2]);
>
Problem 5:
163
p1 := plot(f,x=-2*Pi..0):
>
eq:=x^2+y^2+a*x+b*y-c;
eq := x2 + y 2 + ax + by − c
>
eq1:=subs(x=1,y=1,eq);
eq1 := 2 + a + b − c
>
eq2:=subs(x=3,y=-1,eq);
>
eq3:=subs(x=6,y=4,eq);
eq2 := 10 + 3 a − b − c
>
eq3 := 52 + 6 a + 4 b − c
coef:=solve(eq1=0,eq2=0,eq3=0,a,b,c);
31
coef := b = − 15
4 , c = −19/2, a = − 4
circle:=subs(coef,eq);
>
15
circle := x2 + y 2 − 31
4 x − 4 y + 19/2
implicitplot(circle,x=-10..10,y=-10..10,grid=[50,50]);
>
164
2.17
Calculus Lab 3
Problem # 1
Suppose a rubber band is stretched and the following data is recorded relating the restoring force to displacement.
Displacement (m)
Force (N)
.01
.21
.02
.42
.03
.63
.05
.83
.06
1.0
.08
1.3
.10
1.5
.13
1.7
.16
1.9
.18
2.1
.21
2.3
.25
2.5
.28
2.7
Determine whether this data is best approximated using a linear, quadratic, or logarithmic curve fit (the
logarithmic fit should be of the form y = a + b ln(x + 1)). In each case, plot the data against the curve. In
addition, compute the predicted values for the for the force (given the curve fitting equation) corresponding
to the displacement values in the table. Is there a relationship between the average of the predicted values
and the average of the force values in the table?
Problem # 2
(i) Differentiate these expressions in Maple.
(a)
t2 +1
t3 −1
2
(b) cos (t3 + 1)
(ii) Assign the expression r3 + sin(r) cos(r) to the variable f . Then differentiate with respect to r.
(iii) Assign the expression a sin(x2 ) + b cos(x2 ) to the variable f . Differentiate f with respect to x (here a
and b are constants). Now differentiate f with respect to a (with x and b constant).
Problem # 3
Graph the equations y = x2 and x4 + 4x + 2y 2 + 6y = 12 on the same plot. Find the point(s) of intersection
of these graphs. For each of intersection, find the acute angle between the tangent lines of both equations.
Problem # 4
(i) Find the point on the graph of y = x2 tan(x) that is closest to the point (2.1, 0.8). Hint: Use the
distance formula to obtain a function that describes the distance between the point (2.1, 0.8) and a
typical point (x, x2 tan(x)) on the graph of y and then find its minimum.
(ii) Find the closest point on the parabola y =
x2
4
− 1 to the point (2, −1).
Problem # 5
A metal box with a square base and no top holds 1000 cm3 . It is formed by folding up the sides of the
flattened pattern pictured here and seaming up the four sides. The material for the box costs $1.00/m2 and
the cost to seam the sides is $0.05/m. Find the dimensions of the box that costs the least to produce.
165
Solutions
166
2.18
Calculus Lab 4
Problem # 1
Use Maple to evaluate the following integrals.
R √
(a) x x2 + 1 dx
R
(b) cos4 (x) dx
R
(c) sin6 (x) dx
Problem # 2
R 2 tan−1 (x)
(a) Evaluate the integral x (1+x
dx. First try the value command by itself. Then use the changevar,
2 )2
value, subs, and simplify commands. Be sure to check your answer.
√
R
(b) Evaluate the integral x ln(x+ 1 + x2 ) dx. First try the value command by itself. Then use intparts
and value commands with u = x. Finally, use the intparts and value commands with u = ln(x +
√
1 + x2 ). Be sure to check your answer.
Problem # 3
(i) Find the area of the region that is bounded above by the curves y = ln(x) and y = 4 − x3 − x and
below the x-axis.
(ii) Find the volume of the solid obtained by revolving this region about the x-axis.
(iii) Find the volume of the solid obtained by revolving this region about the line y = 4.
Problem # 4
Suppose you are an engineer who has been assigned a job of designing a hinged valve in a dam (see the
figure). The valve consists of a hinged circular disk of radius 2 m. The center of the disk is located 4 m
below the water surface.
For the purpose of design you need to remember several definitions:
1. Hydrostatic force on the valve, F :
b
Z
F =
ρ(x)gxL(x)dx,
a
where ρ(x) is the water density, g is the gravity acceleration, x is the depth computed from the water
surface, and L(x) is the length of the valve at depth x.
2. Hydrostatic Moment about the hinge, M :
Z
M=
b
ρ(x)gx(x − d)L(x)dx.
a
THINGS TO DO:
Assume ρ(x) = 1000 kg/m3 and g = 9.81 m/sec2 .
1. Compute the hydrostatic force on the valve.
2. Compute the hydrostatic moment about the hinge if the hinge is located at the top of the valve.
3. Compute the hydrostatic moment about the hinge if the hinge is located along the horizontal diameter
of the valve.
167
Figure 2.1: Illustration of the valve inside a dam
4. Compute the vertical location of the hinge ( d ) at which the hydrostatic force on the top half of the
valve is equal to the hydrostatic force on the bottom half of the valve.
5. Compute the vertical location of the hinge ( d ) at which the hydrostatic moment about it is zero.
Do similar computation for ρ(x) = 1100 ∗ exp(0.1x).
168
Solutions
169
2.19
Calculus Lab 5
Problem # 1
This assignment is aimed to investigate the convergence behavior of sequences and series. For this purpose we will use two procedures named ComputeValues and DrawGraphs. Type the following MAPLE
commands.
>
restart:
with(plots):
Warning, the name changecoords has been redefined
>
>
>
>
>
>
>
>
>
>
>
>
>
>
ComputeValues:=proc(a,N)
local M,n,s:
M:=matrix(N+2,3,(Row,Col)->0):
M[1,1]:=n: M[1,2]:=a_n: M[1,3]:=s_n:
s:=n->sum(a(i),i=1..n):
for n from 1 to N do
M[n+1,1]:=n: M[n+1,2]:=evalf(a(n)): M[n+1,3]:=evalf(s(n)):
od:
n:=’n’:
M[N+2,1]:=infinity:
M[N+2,2]:=evalf(limit(a(n),n=infinity)):
M[N+2,3]:=evalf(limit(s(n),n=infinity)):
RETURN(eval(M)):
end:
170
>
>
>
>
>
>
>
DrawGraphs:=proc(a,N)
local apts,s,spts,n:
s:=n->sum(a(i),i=1..n):
apts:=seq([n,a(n)],n=1..N):
spts:=seq([n,s(n)],n=1..N):
plot({apts,spts},n=1..N,style=point);
end:
There are two arguments in these procedures. The first argument (a) is the sequence which should be written
as a function. The second argument (N ) is the number of sequences. For example we want to investigate
∞
1
n n=1
∞
X
1
.
n
n=1
To use the procedures (once you have written the commands above), type the following:
>
>
>
a:=n->1/n;
ComputeValues(a,20);
DrawGraphs(a,20);
What did you see as the output? Use the procedures above ( with N = 20 ) to investigate the convergence
of the following sequences and their corresponding series. State for each of these pairs if they converge or
diverge.
∞
∞
X
1
1
n
2 n=1
2n
n=1
1
n(n + 1)
{ln(n + 1) −
n
n+1
∞
X
∞
n=1
1
n(n
+ 1)
n=1
∞
X
∞
n=1
n
n
+
1
n=1
∞
X
∞
ln(n)}n=1
(ln(n + 1) − ln(n))
n=1
−3
π
n ∞
n
∞ X
−3
n=1
n=1
∞ X
n
o∞
2
ne−n
n=1
π
ne−n
2
n=1
Problem # 2
Write a MAPLE procedure to find the solution of f (x) = 0 using Newton’s method. You should write the
procedure in the following form,
Newton:=proc(func,xinit,TOL,MAXITER)
where
• func is the function f (x) you would like to solve,
171
• xinit is the initial guess,
• TOL is the desired tolerance,
• MAXITER is the maximum number of Newton iterations allowed.
Your procedure should output three parameters, i.e., the solution xr, the value of f (xr), and number of
iterations taken. Recall that Newton’s method is an iterative procedure to solve f (x) = 0 using the following
relation:
f (xn )
xn+1 = xn − 0
,
n = 0, 1, 2, · · · .
f (xn )
where an initial guess x0 is given. In your procedure you should stop the iteration after it reaches the desired
tolerance. In this case, write a conditional statement to stop the iteration if |f (xn )| < TOL. In the case
the number of iterations has reached MAXITER but the desired tolerance has not yet been satisfied, then
your procedure should give a warning statement that the Newton’s method does not converge. Test your
procedure to find all roots of the following functions:
f (x) = 10x4 + 4x3 − 0.4x2 − 0.01x + 0.007
f (x) = x3 − 4.3x2 + 5.83x − 2.541
f (x) = x4 − 18x3 + 4x2 + 738x + 650.
Compare your results with MAPLE built in command.
Problem # 3
Let xstep(i) be the Newton’s method step at the i-th iteration. Comment on the convergence of Newton’s
method in all cases by tabulating xstep(i)/xstep(i-1) and xstep(i)/xstep(i-1)2 for all roots found in
Problem 1.
172
2.20
Calculus Lab 6
Redo the Problem 2 and 3 of Laboratory Assignment 5 for the Secant Method. Problem # 1
Secant:=proc(func,xinitone,xinittwo,TOL,MAXITER)
where
• func is the function f (x) you would like to solve,
• xinitone is the first initial guess,
• xinittwo is the second initial guess,
• TOL is the desired tolerance,
• MAXITER is the maximum number of Newton iterations allowed.
Recall that Secant method is an iterative procedure to solve f (x) = 0 using the following relation:
xn =
xn−2 f (xn−1 ) − xn−1 f (xn−2 )
f (xn−1 ) − f (xn−2 )
n = 2, · · · .
where initial guesses x0 and x1 are given.
Problem # 2
Legendre Polynomials satisfy the following recurrence relation
L0 (x) = 1
L1 (x) = x
Ln (x) =
(n − 1)(xLn−1 (x) − Ln−2 (x))
+ xLn−1 (x),
n
n = 2, 3, · · · , .
Write a procedure to compute the Legendre polynomials Ln (x). Test your procedure to compute L7 (x) and
R1
L40 (x). Compute −1 Ln (x)Lm (x)dx for m 6= n.
173
2.21
Calculus Lab 7
Problem # 1
A simple way of computing the area under the curve y = f (x) over interval [a, b] is using the so-called
Trapezoidal Rule (see left hand side of the figure):
Z
b
f (x) dx ≈
Area =
a
b−a
(f (a) + f (b)).
2
Obviously this is a very crude approximation. Instead we do the following. Divide the interval [a, b] into M
b−a
subintervals, where each subinterval (xi−1 , xi ) has width h =
, for i = 1, 2, · · · , M (see right hand side
M
of the figure). Note that x0 = a and xM = b. Next apply the Trapezoidal Rule to each of the subinterval
(xi−1 , xi ):
h
xi − xi−1
(f (xi−1 ) + f (xi )) = (f (xi−1 ) + f (xi )).
Ti =
2
2
Then the area under the curve y = f (x) over interval [a, b] is the sum of all Ti :
T ≈
M
X
Ti .
i=1
This scheme is called Composite Trapezoidal Rule. Your task is to write a procedure in MAPLE implementing
this method. The procedure should be of the following form:
CompTrapRule:=proc(func,a,b,M)
where
• func is the function f (x) that govern the curve,
• a is the lower limit of the interval,
• b is the upper limit of the interval,
• M is the number of subintervals.
Remark: Direct implementation of the above approximation is not fully efficient because for all internal
points, i.e., xi , i = 1, · · · , M − 1, the function is computed twice. We may actually rewrite the method so
174
that the procedure is more efficient. Expansion of the sum described above yields the following:
T ≈
M
X
Ai
i=1
=
M
h X
(f (xi−1 ) + f (xi ))
2 i=1
h
{(f (x0 ) + f (x1 )) + (f (x1 ) + f (x2 )) + (f (x2 ) + f (x3 )) + · · · + (f (xM −1 ) + f (xM ))}
2
M
−1
X
h
= (f (a) + f (b)) + h
f (xi ).
2
i=1
=
This last expression should be implemented in your procedure.
Problem # 2
This problem is intended to investigate the error of the Composite Trapezoidal Rule. It is known that in the
case that the second derivative of f is continuous over the interval [a, b], there exists a point c ∈ (a, b) such
that the error of the Composite Trapezoidal Rule can be expressed as
Z b
1
ET =
f (x) dx − T = − (b − a) f 00 (c)h2 .
12
a
This expression says that the error associated with approximation of the area using Composite Trapezoidal
Rule is proportional to the square of the subinterval width. Write a procedure to compute the error of the
Composite Trapezoidal Rule. This procedure should call the CompTrapRule(func,a,b,M) that is described
in Problem 1. As such, the procedure should be of the following form:
CompTrapRuleError:=proc(func,a,b)
where all the arguments are as in Problem 1. Your procedure should output a table with the following
parameters on its columns:
|
n
|
M
|
h
|
T
|
ET
|
order
|,
where n is an index, M, h, and T are as before. The parameter ET is the corresponding error computed as
Z b
Z b
f (x) dx − T. Use MAPLE command to compute the exact value of
f (x) dx. The parameter order is
a
a
computed as follows:
order[n] =
DE[n]
,
Dh[n]
where
DE[n] = log |ET [n]| − log |ET [n-1]|
and
Dh[n] = log (h[n]) − log (h[n-1]) .
Test your procedures to compute the integrals
Z 6
√
(2 + sin(2 x)) dx
1
and
Z
2
(x − ln(x)) dx.
0.1
Use M=2,4,8,16,32,64,128,256. Explain your observation.
175
2.22
Calculus Lab 8
Problem # 1
Redo Laboratory Exercise # 7 for the so-called Composite Simpson Rule. For an interval [a, b] Simpson
Rule is expressed as
a+b
b−a
f (a) + 4f (
) + f (b) .
Area ≈
6
2
The Composite Simpson Rule is implemented as follows. Divide [a, b] into 2M subintervals (xi−1 , xi ) of
b−a
equal width h =
. This way we should have xi = a + ih, with i = 0, 1, 2, · · · , 2M . After applying the
2M
Simpson Rule to each of the subintervals, the Composite Simpson Rule can be written as
S=
M −1
M
2h X
4h X
h
(f (a) + f (b)) +
f (x2i ) +
f (x2i−1 ).
3
3 i=1
3 i=1
The procedure should be of the following form:
CompSimpRule:=proc(func,a,b,M)
where
• func is the function f (x) that govern the curve,
• a is the lower limit of the interval,
• b is the upper limit of the interval,
• M is the number of subintervals.
It is known that in the case that the fourth derivative of f is continuous over the interval [a, b], there exists
a point c ∈ (a, b) such that the error of the Composite Simpson Rule can be expressed as
Z b
1
ES =
(b − a) f (4) (c)h4 .
f (x) dx − S = −
180
a
This expression says that the error associated with approximation of the area using Composite Simpson
Rule is proportional to the of the subinterval width raised to the fourth. Write a procedure similar to the
last exercise to compute the error of the Composite Simpson Rule. Test your procedures to compute the
integrals
Z 6
√
(2 + sin(2 x)) dx
1
and
Z
2
(x − ln(x)) dx.
0.1
Use M=1,2,4,8,16,32,64,128. Explain your observation. How does it compare with the Composite Trapezoidal Rule?
Problem # 2
Suppose we would like to compute the area under the curve y = f (x) over an interval [a, b]. A very crude
approximation is
Ao = (a − b) ∗ (fp − fm ),
where fm and fp is the range of the y-axis over the interval [a, b]. In general, fp is the largest value of
f (x) over the interval [a, b]. For this problem we always assume that fm = 0, meaning that we compute
an area which is bounded above by the curve f (x) and below by the x-axis. Obviously this is always an
overestimation. What we actually need is a fraction of Ao . We can do this by applying the Monte Carlo
simulation. The procedure can be implemented in MAPLE as follows:
176
• Set a variable called acceptance := 0.
• On the interval [a, b] determine fp and fm .
• For M times do the following:
– Generate a random number rx such that a ≤ rx ≤ b. We can use MAPLE command rand() for
this purpose. When invoking this command, MAPLE generates a large integer number. To get a
real number that is in the interval [a, b], we can use the following transformation:
rx := a + (b − a) ∗
rand()
.
1012
– Generate a random number ry such that fm ≤ ry ≤ fp . Again we can use rand(), and the
transformation
rand()
ry := fm + (fp − fm ) ∗
.
1012
– If ry < f (rx ) do acceptance := acceptance + 1.
• The area under curve is approximated as
Area := (b − a) ∗ (f (b) − f (a))
acceptance
M
Write a procedure implementing this computation. Your procedure should be as follows:
MonteCarloInt:=proc(func,a,b,M)
where
• func is the function f (x) that govern the curve,
• a is the lower limit of the interval,
• b is the upper limit of the interval,
• M is the number of simulations.
Similar to the previous laboratory exercise, create a table of the following form:
|
n
|
M
|
A
|
Emc
|
order
|,
where n is an index, M, and Area are as before. The parameter Emc is the corresponding error computed as
Z b
f (x) dx − Area. The parameter order is computed as follows:
a
order[n] =
DE[n]
,
DM[n]
where
DE[n] = log |Emc [n]| − log |Emc [n-1]|
and
DM[n] = log (M[n-1]) − log (M[n]) .
Test your procedures by computing the integrals from the previous laboratory exercise. Use M=500,1000,2000,4000,8000,160
What do you observe?
177
2.23
Calculus Lab 9
Problem # 1
This problem is intended to write a MAPLE procedure for solving the following initial value problem:

00
0

y (x) + αy (x) + βy(x) = r(x)
(2.1)
y(0) = p

 0
y (0) = q
where y 00 =
d2 y
and y 0 =
dx2
dy
dx ,
α and β are given constants, p and q are given initial data.
1. Solve the homogeneous part, i.e., set r(x) = 0 and solve
yh00 (x) + αyh0 (x) + βyh (x) = 0.
(2.2)
Now let z(x) = eθx , take its derivative up to second order and substitute to (2.2). The following
auxiliary equation is the result:
θ2 + αθ + β = 0.
(2.3)
Denote by θ1 and θ2 the roots of this quadratic function, and let us assume that θ1 6= θ2 . Then we
may write the solution of (2.2) as follows:
yh (x) = c1 y1 (x) + c2 y2 (x),
(2.4)
where y1 (x) = eθ1 x and y2 (x) = eθ2 x , and c1 and c2 are constants to be determined later.
2. Solve the nonhomogeneous part i.e., solve
yp00 (x) + αyp0 (x) + βyp (x) = r(x),
(2.5)
yp (x) = u1 (x)y1 (x) + u2 (x)y2 (x),
(2.6)
where
and u1 (x) and u2 (x) to be determined.
3. Computation of u1 (x) and u2 (x). First derivative of yp is
yp0 = u1 y10 + u2 y20 + u01 y1 + u02 y2 .
(2.7)
u01 y1 + u02 y2 = 0.
(2.8)
yp0 = u1 y100 + u2 y200 + u01 y10 + u02 y20 .
(2.9)
Set
Then second derivative of yp is
Substitution of yp , yp0 , and yp00 to (2.5) gives the following equation
u01 y10 + u02 y20 = r(x).
(2.10)
Then we can use (2.8) and (2.10) to solve for u01 and u02 :
r(x) y2 (x)
w(x)
r(x)
y1 (x)
u02 (x) = −
,
w(x)
u01 (x) =
178
(2.11)
with w(x) = y10 (x) y2 (x) − y1 (x) y20 (x), from which we obtain
Z
r(x) y2 (x)
u1 (x) =
dx
w(x)
Z
r(x) y1 (x)
u2 (x) = −
dx.
w(x)
(2.12)
4. The final solution is
y(x) = yh (x) + yp (x),
(2.13)
where yh (x) and yp (x) are as before. Now recall that yh contains constants c1 and c2 which needs to
be determined. The only thing left is the initial data. There are two initial data and two unknowns,
so we can set
c1 y1 (0) + c2 y2 (0) + yp (0) = p
c1 y10 (0) + c2 y20 (0) + yp0 (0) = q,
(2.14)
which can be solved for c1 and c2 .
Write a MAPLE procedure implementing this procedure. Your procedure should be of the following form:
SecondOrderODESolver:=proc(alpha,beta,r,p,q),
(2.15)
where all the arguments are as in the description explained above. The procedure should contain the
following:
• Solve the auxiliary equation (2.3)
• Solve u1 and u2
• Set the general solution.
• Solve for c1 and c2 .
• Output the solution as a function.
Test your procedure to solve the following problems:
y 00 + 2y 0 − 3y = sin(x), y(0) = 0, y 0 = 0
y 00 − y 0 − 2y = e−2x tan(x), y(0) = 1, y 0 = 0
.
Plot the solutions in some reasonable range.
179
(2.16)
2.24
Calculus Lab 10
Problem # 1
This problem is intended to write a MAPLE procedure for solving the following initial value problem:
(
y 0 (x) + α(x)y(x) = f (x) a < x < b
(2.17)
y(a) = p
dy
, α(x) and f (x) are given functions, and p is given initial data. We shall assume that our
where y 0 = dx
solution is of the following form:
N
X
φ(x) = p +
ci xi ,
(2.18)
i=1
and our task is to determine the value of ci , i = 1, · · · , N . For that, we do the following:
• Take φ0 and φ, substitute them to the ODE, multiply by xi to get the following:
ri (x) = (φ0 (x) + α(x)φ(x) − f (x)) xi
(2.19)
for i = 1, 2, · · · , N .
• Integrate them and set to zero:
Z
b
ri (x) dx = 0,
i = 1, 2, · · · , N.
(2.20)
a
The resulting is an N equations with N unknowns, which can be solved for ci . Write a MAPLE procedure
implementing this procedure. Your procedure should be of the following form:
FirstOrderODESolver:=proc(alpha,f,p,N),
(2.21)
where all the arguments are as in the description explained above. Test your procedure to solve the following
problems:
y 0 + 5y = 1 + x − sin(2x), y(0) = 0,
x ∈ (0, 3)
(2.22)
The analytical solution of this problem is
y(x) =
1
(116 + 559 exp(−5x) + 145x + 50 cos(2x) − 125 sin(2x)) .
725
(2.23)
Test your procedure for N = 7, 14. Then plot the solutions with the analytical solution in the same graph.
Plot also the error of the solutions, i.e., the function
e(x) = y(x) − φ(x).
NOTE: In writing your procedure, if at all possible avoid using evalf.
180
(2.24)
Chapter 3
C-Programming
C is a programming language. That means, the user writes some code, that code is translated into an
executable program, and then that program can be run on the machine just like any other program. In some
cases (especially on Windows operating system), the process of writing, compiling and running a program
is collated into one by means of C-programming environment, which is a program that lets the user do all
these things through menu functions. Apart from that, the code that is written is somewhat standard and
should be portable between different systems. The C-language is mainly due to Kernighan and Ritchie from
the late 60s. The core language is still the same. Nevertheless, new things have been built on to of that.
For instance, C++ is another language which incorporates C. That is, any C-program can also run in C++
(but not conversely). Also, libraries have been developed that can be used from within a C-program. That
way, C is made more powerful.
In these notes, we show only the plain C-code. If you have a C-environment, you can compile and run
the code using the provided menu options. In a plain environment, you need to compile and run the program
by yourself, i.e. by invoking the C-compiler and then by invoking the program that was produced by the
compiler. These steps are somewhat system dependent and we will not discuss them here.
3.1
Hello World
Probably everyone’s first C-program is something similar to this. Typically, C-code resides in files with
extension “.c”. So, we might store the following piece of code in a file called “hello.c”. But this is just a
convention, you may decide to call the file any way you wish.
1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
printf("hello world\n");
}
The output is
1
2
3.2
1
2
3
hello world
Fibonacci Numbers
// ExFibonacci.c
// Fibonacci sequence
// Jiangguo (James) Liu, ColoState, 04/06/07
181
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
int main(void)
{
int i;
long int f1, f2;
f1 = 1;
f2 = 1;
for (i=1; i<20; ++i) {
printf("%12ld
%12ld
", f1, f2);
if (i%2==0) printf("\n");
f1 = f1 + f2;
f2 = f1 + f2;
}
printf("\n");
return (0);
}
The output is
1
2
3
4
5
6
7
8
9
10
11
1
5
34
233
1597
10946
75025
514229
3524578
24157817
3.3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
1
8
55
377
2584
17711
121393
832040
5702887
39088169
2
13
89
610
4181
28657
196418
1346269
9227465
3
21
144
987
6765
46368
317811
2178309
14930352
A Simple Encryption Scheme
//
//
//
//
//
//
//
//
encrypt.c
A simple scheme for encryption: Scheme 1
gcc encrypt.c
a.out
Jiangguo (James) Liu, ColoState, 04/09/07
#include <stdio.h>
int main(void)
{
char c;
while ((c=getchar()) != ´\n´) {
if ((c>=´A´ && c<=´Z´) || (c>=´a´ && c<=´z´)) {
c += 3;
if ((c>´Z´ && c<=´Z´+3) || c>´z´) c-=26;
}
printf("%c", c);
}
printf("\n");
return (0);
}
After running the program, type
182
1
2
gallia omnis divisa est in partes tres
It is important to end the input with a “return”. The output is
1
2
jdoold rpqlv glylvd hvw lq sduwhv wuhv
3.4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Roots of a Quadratic Polynomial
//
//
//
//
ExQuaRoots.c
Find the roots of a quadratic equation
gcc QuaRoots.c -lm
Jiangguo (James) Liu, ColoState, 04/04/07
#include <math.h>
#include <stdio.h>
int main(void)
{
double a, b, c, d, r1, r2;
double alpha, beta;
printf("Type in the 3 coefficients a, b, c:\n");
scanf("%lf%lf%lf", &a, &b, &c); // Must use %lf
printf("Verify the 3 coefficients:\n");
printf("a=%f b=%f c=%f\n", a, b, c);
if (a==0) {
printf("This is not a quadratic, quit!\n");
return (1);
}
d = b*b-4*a*c;
if (d>0) {
r1 = (-b-sqrt(d))/(2*a);
r2 = (-b+sqrt(d))/(2*a);
printf("Two different real roots:\n");
printf("root1=%f root2=%f\n", r1, r2);
}
if (d==0) {
r1 = -b/(2*a);
r2 = r1;
printf("Two identical real roots:\n");
printf("root1=root2= %f\n", r1, r2);
}
if (d<0) {
alpha = -b/(2*a);
beta = sqrt(-d)/(2*a);
printf("Two conjugate complex roots:\n");
printf("%f (+-i) %f\n", alpha, beta);
}
return (0);
}
After running the program, type
1
2
1 0 1
It is important to end the input with a “return”. The output is
183
1
2
3
4
5
6
3.5
Type in the 3 coefficients a, b, c:
Verify the 3 coefficients:
a=1.000000 b=0.000000 c=1.000000
Two conjugate complex roots:
-0.000000 (+-i) 1.000000
Two-Dimensional Geometry
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// geo2d.h
// Declarations for 2-dim geometry
// Jiangguo (James) Liu, ColoState, 05/01/07
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// geo2d.cpp
// Source code for 2-dim geometry
// Jiangguo (James) Liu, ColoState, 05/01/07
#include <math.h>
class PtVec2d {
public:
double x, y;
public:
PtVec2d(double a=0, double b=0) {x=a; y=b;} // constructor
double length() const {return sqrt(x*x+y*y);}
friend double dist(const PtVec2d &P1, const PtVec2d &P2);
friend PtVec2d operator+(const PtVec2d &V1, const PtVec2d &V2);
friend PtVec2d operator-(const PtVec2d &V1, const PtVec2d &V2);
friend PtVec2d operator*(double a, const PtVec2d &V);
friend double dotProd(const PtVec2d &V1, const PtVec2d &V2);
};
class Trig {
public:
PtVec2d vrtx[3];
public:
Trig(PtVec2d A, PtVec2d B, PtVec2d C);
double area() const;
PtVec2d center() const;
bool isInTrig(PtVec2d P) const;
};
// constructor
#include <math.h>
#include "geo2d.h"
double dist(const PtVec2d &P1, const PtVec2d &P2)
{
double xtmp = P1.x-P2.x;
double ytmp = P1.y-P2.y;
return sqrt(xtmp*xtmp+ytmp*ytmp);
}
PtVec2d operator+(const PtVec2d &V1, const PtVec2d &V2)
{
return PtVec2d(V1.x+V2.x, V1.y+V2.y);
}
PtVec2d operator-(const PtVec2d &V1, const PtVec2d &V2)
{
return PtVec2d(V1.x-V2.x, V1.y-V2.y);
}
184
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
PtVec2d operator*(double a, const PtVec2d &V)
{
return PtVec2d(a*V.x, a*V.y);
}
double dotProd(const PtVec2d &V1, const PtVec2d &V2)
{
return (V1.x*V2.x + V1.y*V2.y);
}
Trig::Trig(PtVec2d A, PtVec2d B, PtVec2d C)
{
vrtx[0] = A;
vrtx[1] = B;
vrtx[2] = C;
}
double Trig::area() const
{
double x1 = vrtx[0].x;
double y1 = vrtx[0].y;
double x2 = vrtx[1].x;
double y2 = vrtx[1].y;
double x3 = vrtx[2].x;
double y3 = vrtx[2].y;
return 0.5*fabs((x2-x1)*(y3-y1)-(x3-x1)*(y2-y1));
}
PtVec2d Trig::center() const
{
return (1.0/3)*(vrtx[0]+vrtx[1]+vrtx[2]);
}
bool Trig::isInTrig(PtVec2d P) const
{
bool b = false;
Trig T1(P, vrtx[1], vrtx[2]);
Trig T2(vrtx[0], P, vrtx[2]);
Trig T3(vrtx[0], vrtx[1], P);
if (T1.area()+T2.area()+T3.area()==area())
b = true;
return b;
}
//
//
//
//
//
ExGeo2d.cpp
Examples for geometry 2-dim
C++ compilation commands on Unix/Linux:
g++ ExGeo2d.cpp geo2d.cpp -lm
Jiangguo (James) Liu, ColoState, 05/01/07
#include <math.h>
#include <stdio.h>
#include "geo2d.h"
int main()
{
PtVec2d A, B(1,0), C(0,1), cntr;
Trig T(A,B,C);
printf("The distance bewteen A and B is %9.6f\n", dist(A,B));
185
17
18
19
20
21
22
23
printf("The distance between the center and A is ");
printf("%9.6f\n", dist(T.center(),A));
printf("Triangle area = %9.6f\n", T.area());
return 0;
}
To compile, type g++ ExGeo2d.cpp geo2d.cpp
1
2
3
4
The distance bewteen A and B is 1.000000
The distance between the center and A is 0.471405
Triangle area = 0.500000
3.6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Home-Grown Square Roots
//
//
//
//
ExHomeSqrt.c
Home-grown square roots
gcc ExHomeSqrt.c -lm
Jiangguo (James) Liu, ColoState, 04/11/07
#include <math.h>
#include <stdio.h>
int main(void)
{
int itr;
double a, threshold, xnew, xold;
printf("Type in a positive number and a threshold:\n");
scanf("%lf %lf", &a, &threshold);
itr = 0;
xold = 1;
while (1) {
itr++;
xnew = 0.5*(xold + a/xold);
if (fabs(xnew-xold)<threshold)
xold = xnew;
}
printf("Number of iterations =
printf("Home-grown square root
printf("Built-in square root
printf("The difference is
break;
%d\n", itr);
= %21.15f\n", xnew);
= %21.15f\n", sqrt(a));
= %21.15f\n", xnew-sqrt(a));
return (0);
}
After running the program, type
1
2
2 0.0000000001
1
2
3
4
5
6
Type in a positive number and a threshold:
Number of iterations = 5
Home-grown square root =
1.414213562373095
Built-in square root
=
1.414213562373095
The difference is
=
-0.000000000000000
186
3.7
Horner’s Algorithm for Polynomials
1
2
3
4
5
6
7
8
9
10
11
12
// poly.h
// Function decalarations for polynomials
// Jiangguo (James) Liu, ColoState, 04/14/07
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// poly.c
// Functions for polynomials
// Jiangguo (James) Liu, ColoState, 04/18/07
1
2
3
4
//
//
//
//
double polya(double x, int n, double a[]);
double derivPolya(double x, int n, double a[]);
double polyp(double x, int n, double *p);
double derivPolyp(double x, int n, double *p);
// Polynomial implemented based on 1-dim array
double polya(double x, int n, double a[])
{
int i;
double y=0;
for (i=n; i>=0; --i) y = y*x + a[i];
return y;
}
// Polynomial derivative implemented based on 1-dim array
double derivPolya(double x, int n, double a[])
{
int i;
double z=0;
for (i=n; i>=1; --i) z = z*x + i*a[i];
return z;
}
// Polynomial implemented based on pointer
double polyp(double x, int n, double *p)
{
int i;
double y=0;
for (i=n; i>=0; --i) y = y*x + p[i];
return y;
}
// Polynomial derivative implemented based on pointer
double derivPolyp(double x, int n, double *p)
{
int i;
double z=0;
for (i=n; i>=1; --i) z = z*x + i*p[i];
return z;
}
ExPolya.c
An example for polynomials based on 1-dim arrays
gcc ExPolya.c poly.c
also single commands for compilation and linking
187
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// Jiangguo (James) Liu, ColoState, 04/14/07
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
//
//
//
//
//
#include <stdio.h>
#include "poly.h"
int main(void)
{
const int maxDeg = 10;
int i, j, n;
double a[maxDeg+1];
double x[5], y;
printf("Type in the degree of the polynomial (<=10):\n");
scanf("%d", &n);
printf("Type in the coefficients (descending order): \n");
for (i=n; i>=0; --i) scanf("%lf", &a[i]);
// Evaluate and print out the polynomial values and derivatives
// at 5 specified points
printf("
Point
Poly value
Derivative\n");
for (j=0; j<5; ++j) {
x[j] = j-2;
y = polya(x[j], n, a);
printf("%10.3f
%10.3f
%10.3f\n", x[j], y, derivPolya(x[j],n,a));
}
return (0);
}
ExPolyp.c
An example for polynomials
based on pointers and dynamic memory allocation
g++ -c ExPolyp.c
Jiangguo (James) Liu, ColoState, 04/14/07
#include <stdio.h>
#include <stdlib.h>
#include "poly.h"
int main(void)
{
int i, j, n;
double *p;
double x[5];
printf("Type in the degree of the polynomial:\n");
scanf("%d", &n);
p = malloc(n*sizeof(double));
for (i=n; i>=0; --i) p[i] = 0.0;
printf("Type in the coefficients (descending order): \n");
for (i=n; i>=0; --i) scanf("%lf", p+i);
// Evaluate and print out the polynomial values and derivatives
// at 5 specified points
printf("
Point
Poly value
Derivative\n");
for (j=0; j<5; ++j) {
x[j] = j-2;
printf("%10.3f
", x[j]),
printf("%10.3f
", polyp(x[j],n,p));
printf("%10.3f\n", derivPolyp(x[j],n,p));
}
free(p);
return (0);
}
188
39
1
2
3
4
5
6
7
8
9
10
11
3.8
Type in the degree of the polynomial (<=10):
6
Type in the coefficients (descending order):
1 2 3 4 5 6 7
Point
Poly value
Derivative
-2.000
31.000
-94.000
-1.000
4.000
0.000
0.000
7.000
6.000
1.000
28.000
56.000
2.000
247.000
522.000
Lily Numbers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// ExLily.c
// Find the 3-digit lily numbers
// Jiangguo (James) Liu, ColoState, 04/11/07
1
2
3
4
5
Lily
Lily
Lily
Lily
3.9
#include <stdio.h>
int main(void)
{
int i, j, k, n;
for (i=1; i<=9; ++i) {
for (j=0; j<=9; ++j) {
for (k=0; k<=9; ++k) {
n = i*100 + j*10 + k;
if (n==(i*i*i+j*j*j+k*k*k)) {
printf("Lily number: %d\n", n);
}
}
}
}
return 0;
}
number:
number:
number:
number:
153
370
371
407
Two by Two Matrices
1
2
3
4
5
6
7
8
9
10
11
12
// mat2.h
// The header file for 2-by-2 real double matrices
// Jiangguo (James) Liu, ColoState, 04/18/07
1
2
// mat2.c
// 2-by-2 double matrices
void mat2scanf(double A[][2]);
void mat2printf(double A[][2]);
double mat2det(double A[][2]);
int mat2inv(double A[][2], double B[][2]);
189
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// Jiangguo (James) Liu, ColoState, 04/18/07
1
2
3
4
5
6
7
8
9
10
11
// ExMat2.c
// Examples for 2-by-2 double matrices
// Jiangguo (James) Liu, ColoState, 04/18/07
#include <stdio.h>
#include <stdlib.h>
void mat2scanf(double A[][2])
{
printf("Type in the 2-by-2 matrix:\n");
printf("1st row: ");
scanf("%lf %lf", &A[0][0], &A[0][1]);
printf("2nd row: ");
scanf("%lf %lf", &A[1][0], &A[1][1]);
return;
}
void mat2printf(double A[][2])
{
printf("\n");
printf("The 2x2 matrix is: \n");
printf("%12.6f
%12.6f\n", A[0][0], A[0][1]);
printf("%12.6f
%12.6f\n", A[1][0], A[1][1]);
return;
}
double mat2det(double A[][2])
{
double d;
d = A[0][0]*A[1][1]-A[0][1]*A[1][0];
return d;
}
// A is the given matrix, B is the inverse matrix
int mat2inv(double A[][2], double B[][2])
{
double det;
det = mat2det(A);
if (det==0) {
printf("The determinat is zero, no inverse, quit!\n");
B[0][0]=0; B[0][1]=0; B[1][0]=0; B[1][1]=0;
return(EXIT_FAILURE);
}
else {
B[0][0] = A[1][1]/det;
B[0][1] = -A[0][1]/det;
B[1][0] = -A[1][0]/det;
B[1][1] = A[0][0]/det;
}
return(EXIT_SUCCESS);
}
#include <stdio.h>
#include <stdlib.h>
#include "mat2.h"
int main()
{
double det;
190
12
13
14
15
16
17
18
19
20
21
22
23
24
25
double A[2][2], B[2][2];
mat2scanf(A);
mat2printf(A);
printf("\nThe determinant is: %12.6f\n", mat2det(A));
mat2inv(A, B);
mat2printf(B);
printf("\n");
return(EXIT_SUCCESS);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Type in the 2-by-2 matrix:
1st row: 0 1
2nd row: 1 0
3.10
Perfect Numbers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ExPerfectNums.c
// Find the perfect numbers within 2000
// Jiangguo (James) Liu, ColoState, 04/09/07
1
2
3
4
6
28
496
3.11
Computing Pi
1
2
3
4
// ExPi.c
// A simple formula for computing pi
// Jiangguo (James) Liu, ColoState, 04/09/07
The 2x2 matrix is:
0.000000
1.000000
The determinant is:
1.000000
0.000000
-1.000000
The 2x2 matrix is:
-0.000000
1.000000
1.000000
-0.000000
#include <stdio.h>
int main(void)
{
int m, n, sum;
for (m=1; m<=2000; ++m) {
sum = 0;
for (n=1; n<m; ++n) {
if (m%n==0) sum += n;
}
if (m==sum) printf("%i\n", m);
}
return (0);
}
191
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <math.h>
#include <stdio.h>
1
2
n=100000001
3.12
Computing Primes: the Naive Way
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// ExPrimesNaive.c
// Generating prime numbers by a naive method
// Jiangguo (James) Liu, ColoState, 04/09/07
int main(void)
{
long int n;
int s;
double pi, t;
n = 1;
pi = 0;
s = 1;
t = 1;
while (fabs(t)>1E-8) {
pi = pi + t;
n += 2;
s = -s;
t = s/(double)n;
}
pi *=4;
printf("n=%ld ", n);
printf("pi=%18.15f\n", pi);
return (0);
}
pi= 3.141592633590251
#include <stdio.h>
#include <stdbool.h>
// <stdbool.h> is not available in Microsoft VC6.0
// change isPrime to a char/int variable taking 0,1
int main(void)
{
int m, n, p, cnt = 0;
bool isPrime;
printf("Generating primes.\n");
printf("Type in the upper bound... ");
scanf("%d", &m);
for (p=2; p<=m; ++p) {
isPrime = true;
for (n=2; n<p; n++) {
if (p%n==0) {
isPrime = false;
break;
}
}
if (isPrime!=false) {
cnt++;
printf("%8d ", p);
if ((cnt % 5) == 0) printf("\n");
}
}
printf("\nFound %d primes up to %d\n", cnt, m);
return 0;
192
36
37
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
Generating primes.
Type in the upper bound... 1000
2
3
5
13
17
19
31
37
41
53
59
61
73
79
83
101
103
107
127
131
137
151
157
163
179
181
191
199
211
223
233
239
241
263
269
271
283
293
307
317
331
337
353
359
367
383
389
397
419
421
431
443
449
457
467
479
487
503
509
521
547
557
563
577
587
593
607
613
617
641
643
647
661
673
677
701
709
719
739
743
751
769
773
787
811
821
823
839
853
857
877
881
883
911
919
929
947
953
967
983
991
997
Found 168 primes up to 1000
3.13
Computing Primes: the Sieve of Erathosthenes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//
//
//
//
7
23
43
67
89
109
139
167
193
227
251
277
311
347
373
401
433
461
491
523
569
599
619
653
683
727
757
797
827
859
887
937
971
11
29
47
71
97
113
149
173
197
229
257
281
313
349
379
409
439
463
499
541
571
601
631
659
691
733
761
809
829
863
907
941
977
ExPrimesSieve.c
Generating prime numbers by the sieve method
of Erastosthenes (an ancient Greek)
Jiangguo (James) Liu, ColoState, 04/11/07
#include <math.h>
#include <stdio.h>
int main(void)
{
int k, m, m1, m2, n;
double s;
printf("Generating primes.\n");
printf("Type in the lower and upper bounds... ");
scanf("%d %d", &m1, &m2);
n = 0;
// Number of primes between m1 and m2
for (m=m1; m<=m2; ++m) {
s = sqrt(m);
for (k=2; k<=s; ++k) {
if (m%k==0) break;
193
24
25
26
27
28
29
30
31
32
33
34
35
36
}
if (k>s && m != 1) {
printf("%8d ", m);
++n;
if ((n % 5) == 0) printf("\n");
}
}
printf("\n");
printf("\nFound %d primes between %d and %d\n", n, m1, m2);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Generating primes.
Type in the lower and upper bounds... 1 1000
2
3
5
7
11
13
17
19
23
29
31
37
41
43
47
53
59
61
67
71
73
79
83
89
97
101
103
107
109
113
127
131
137
139
149
151
157
163
167
173
179
181
191
193
197
199
211
223
227
229
233
239
241
251
257
263
269
271
277
281
283
293
307
311
313
317
331
337
347
349
353
359
367
373
379
383
389
397
401
409
419
421
431
433
439
443
449
457
461
463
467
479
487
491
499
503
509
521
523
541
547
557
563
569
571
577
587
593
599
601
607
613
617
619
631
641
643
647
653
659
661
673
677
683
691
701
709
719
727
733
739
743
751
757
761
769
773
787
797
809
811
821
823
827
829
839
853
857
859
863
877
881
883
887
907
911
919
929
937
941
947
953
967
971
977
983
991
997
3.14
Matrix Multiplication over a Finite Field
1
2
3
4
5
6
7
8
9
10
11
// matrix multiplication over GF(p)
// Anton Betten 8/2007
Found 168 primes between 1 and 1000
#include <stdio.h>
#include <stdlib.h> // for rand(), RAND_MAX
int random_integer(int n);
void identity_matrix(int *A, int n);
void matrix_mult(int *A, int *B, int *C, int n, int p);
void matrix_print(int *A, int n);
194
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
main(int argc, char **argv)
{
int n, p;
int *A, *B, *C;
int i, j, k, a;
if (argc < 2) {
printf("usage %s <n> <p>\n", argv[0]);
printf("where n is the size of the matrix\n");
printf("and p is the size of the Galois field GF(p) we are computing in\n");
}
sscanf(argv[argc - 2], "%d", &n);
sscanf(argv[argc - 1], "%d", &p);
printf("n=%d p=%d\n", n, p);
/*srand(time(0));*/
srand(12345);
A = malloc(n * n * sizeof(int));
B = malloc(n * n * sizeof(int));
C = malloc(n * n * sizeof(int));
identity_matrix(A, n);
identity_matrix(B, n);
for (k = 0; k < 100; k++) {
i = random_integer(n);
j = random_integer(n);
a = random_integer(p);
A[i * n + j] = a;
i = random_integer(n);
j = random_integer(n);
a = random_integer(p);
B[i * n + j] = a;
}
matrix_mult(A, B, C, n, p);
printf("A=\n");
matrix_print(A, n);
printf("B=\n");
matrix_print(B, n);
printf("C=\n");
matrix_print(C, n);
free(A);
free(B);
free(C);
return 0;
}
int random_integer(int n)
// computes a random integer r with $0 \le r < n.$
{
int r;
if (n == 0) {
printf("random_integer n = 0\n");
exit(1);
}
r = (int)(((double)rand() * (double)n / RAND_MAX)) % n;
return r;
}
void identity_matrix(int *A, int n)
{
int i, j;
for (i = 0; i < n;
for (j = 0; j <
if (i == j)
A[i * n +
else
A[i * n +
i++) {
n; j++) {
j] = 1;
j] = 0;
195
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
}
}
}
void matrix_mult(int *A, int *B, int *C, int n, int p)
{
int i, j, k, c, d;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
c = 0;
for (k = 0; k < n; k++) {
d = (A[i * n + k] * B[k * n + j]) % p;
c += d;
c %= p;
}
C[i * n + j] = c;
}
}
}
void matrix_print(int *A, int n)
{
int i, j;
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
printf("%2d", A[i * n + j]);
}
printf("\n");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
n=4 p=5
A=
1 4 1 2
4 1 1 4
1 2 3 1
3 0 0 4
B=
1 3 3 0
2 0 0 2
4 1 0 4
2 2 0 3
C=
2 3 3 3
3 1 2 3
4 3 3 4
1 2 4 2
3.15
Quicksort
1
2
3
4
5
6
7
8
9
10
11
12
13
// quicksort for integer vectors
// Anton Betten 8/2007
#include <stdio.h>
#include <stdlib.h> // for rand(), RAND_MAX
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
196
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
int random_integer(int n);
void partition(int *v, int (*compare_func)(int a, int b),
int left, int right, int *middle);
void quicksort(int *v, int (*compare_func)(int a, int b), int left, int right);
int compare_increasingly(int a, int b);
int compare_decreasingly(int a, int b);
main(int argc, char **argv)
{
int n, m;
int *A;
int i, k, t0, t1, dt;
if (argc < 2) {
printf("usage %s <n> <m>\n", argv[0]);
printf("where n is the length of the vector\n");
printf("and m is the number of vectors that should be sorted\n");
}
sscanf(argv[argc - 2], "%d", &n);
sscanf(argv[argc - 1], "%d", &m);
printf("n=%d m=%d\n", n, m);
/*srand(time(0));*/
srand(12345);
t0 = time(0);
A = malloc(n * sizeof(int));
for (k = 0; k < m; k++) {
for (i = 0; i < n; i++) {
A[i] = random_integer(1000000);
}
quicksort(A, compare_increasingly, 0, m - 1);
if (n <= 10 && m <= 10) {
for (i = 0; i < n; i++) {
printf("%d ", A[i]);
}
printf("\n");
}
}
free(A);
t1 = time(0);
/*printf("t0=%d\n", t0);
printf("t1=%d\n", t1);*/
dt = t1 - t0;
printf("this took %d seconds\n", dt);
return 0;
}
int random_integer(int n)
// computes a random integer r with $0 \le r < n.$
{
int r;
if (n == 0) {
printf("random_integer n = 0\n");
exit(1);
}
r = (int)(((double)rand() * (double)n / RAND_MAX)) % n;
return r;
}
void partition(int *v, int (*compare_func)(int a, int b),
int left, int right, int *middle)
{
int l, r, m, len, m1, res, pivot;
int vv;
197
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//ptintf("partition: from %d to %d\n", left, right);
// pivot strategy: take the element in the middle:
len = right + 1 - left;
m1 = len >> 1;
pivot = left;
if (m1) {
vv = v[pivot];
v[pivot] = v[left + m1];
v[left + m1] = vv;
}
l = left;
r = right;
while (l < r) {
while (TRUE) {
if (l > right)
break;
res = (*compare_func)(v[l], v[pivot]);
if (res > 0)
break;
l++;
}
while (TRUE) {
if (r < left)
break;
res = (*compare_func)(v[r], v[pivot]);
if (res <= 0)
break;
r--;
}
// now v[l] > v[pivot] and v[r] <= v[pivot]
if (l < r) {
vv = v[l];
v[l] = v[r];
v[r] = vv;
}
}
m = r;
if (left != m) {
vv = v[left];
v[left] = v[m];
v[m] = vv;
}
*middle = m;
}
void quicksort(int *v, int (*compare_func)(int a, int b), int left, int right)
{
int middle;
if (left < right) {
partition(v, compare_func, left, right, &middle);
quicksort(v, compare_func, left, middle - 1);
quicksort(v, compare_func, middle + 1, right);
}
}
int compare_increasingly(int a, int b)
{
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
}
int compare_decreasingly(int a, int b)
{
if (a > b)
return -1;
198
152
153
154
155
156
157
158
if (a < b)
return 1;
return 0;
}
3.16
Computing the GCD of Two Integers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// computing the gcd of two integers
// Anton Betten 8/2007
#include <stdio.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
int gcd(int m, int n);
int main(int argc, char **argv)
{
int a, b, g;
if (argc < 2) {
printf("usage %s <a> <b>\n", argv[0]);
printf("computes the gcd of a and b\n");
}
sscanf(argv[argc - 2], "%d", &a);
sscanf(argv[argc - 1], "%d", &b);
g = gcd(a, b);
printf(" The gcd of %d and %d is %d\n", a, b, g);
return 0;
}
int gcd(int m, int n)
{
int r, s;
if (n > m) {
r = m;
m = n;
n = r;
}
if (n == 0) {
return m;
}
while (TRUE) {
s = m / n;
r = m - (s * n);
if (r == 0) {
return n;
}
m = n;
n = r;
}
}
199
3.17
All k-Subsets of an n-Set
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// lists all k-subsets of an n set in lexicographical order
// Anton Betten 8/2007
#include <stdio.h>
#include <stdlib.h> // for malloc
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
void print_set(int *set, int k);
int first_k_subset(int *set, int n, int k);
int next_k_subset(int *set, int n, int k);
int main(int argc, char **argv)
{
int n, k, cnt;
int *set;
if (argc < 2) {
printf("usage %s <n> <k>\n", argv[0]);
printf("lists all k-subsets of an n set in lexicographical order\n");
}
sscanf(argv[argc - 2], "%d", &n);
sscanf(argv[argc - 1], "%d", &k);
set = (int *) malloc(k * sizeof(int));
cnt = 0;
first_k_subset(set, n, k);
do {
printf("%d: ", cnt);
print_set(set, k);
printf("\n");
cnt++;
} while (next_k_subset(set, n, k));
free(set);
return 0;
}
void print_set(int *set, int k)
{
int i;
printf("{ ");
for (i = 0; i < k; i++) {
printf("%d ", set[i]);
}
printf("}");
}
int first_k_subset(int *set, int n, int k)
{
int i;
if (k > n)
return FALSE;
for (i = 0; i < k; i++)
set[i] = i;
return TRUE;
}
int next_k_subset(int *set, int n, int k)
200
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
{
int i, ii, a;
for (i = 0; i < k; i++) {
a = set[k - 1 - i];
if (a < n - 1 - i) {
set[k - 1 - i] = a + 1;
for (ii = i - 1; ii >= 0; ii--) {
set[k - 1 - ii] = set[k - 1 - ii - 1] + 1;
}
return TRUE;
}
}
return FALSE;
}
The 20 3-subsets of the 6-element set {0, 1, 2, 3, 4, 5} are
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0: { 0 1 2 }
1: { 0 1 3 }
2: { 0 1 4 }
3: { 0 1 5 }
4: { 0 2 3 }
5: { 0 2 4 }
6: { 0 2 5 }
7: { 0 3 4 }
8: { 0 3 5 }
9: { 0 4 5 }
10: { 1 2 3 }
11: { 1 2 4 }
12: { 1 2 5 }
13: { 1 3 4 }
14: { 1 3 5 }
15: { 1 4 5 }
16: { 2 3 4 }
17: { 2 3 5 }
18: { 2 4 5 }
19: { 3 4 5 }
3.18
All k-Subsets of an n-Set, 2nd Method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// lists all k-subsets of an n set in lexicographical order by their ranks
// Anton Betten 8/2007
#include <stdio.h>
#include <stdlib.h> // for malloc
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
int binomial_coefficient(int n, int k);
void print_set(int *set, int k);
int rank_k_subset(int *set, int n, int k);
void unrank_k_subset(int rk, int *set, int n, int k);
int main(int argc, char **argv)
{
int n, k, N, cnt, rk;
201
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
int *set;
if (argc < 2) {
printf("usage %s <n> <k>\n", argv[0]);
printf("lists all k-subsets of an n set in lexicographical order by their ranks\n");
}
sscanf(argv[argc - 2], "%d", &n);
sscanf(argv[argc - 1], "%d", &k);
set = (int *) malloc(k * sizeof(int));
cnt = 0;
N = binomial_coefficient(n, k);
for (cnt = 0; cnt < N; cnt++) {
unrank_k_subset(cnt, set, n, k);
rk = rank_k_subset(set, n, k);
printf("%d : ", cnt);
print_set(set, k);
printf(" : %d\n", rk);
if (cnt != rk) {
printf("cnt != rk, something is very wrong\n");
exit(1);
}
}
free(set);
return 0;
}
int binomial_coefficient(int n, int k)
{
if (k == 0)
return 1;
if (n == 0) {
if (k == 0)
return 1;
else
return 0;
}
else
return binomial_coefficient(n - 1, k - 1) * n / k;
}
void print_set(int *set, int k)
{
int i;
printf("{ ");
for (i = 0; i < k; i++) {
printf("%d ", set[i]);
}
printf("}");
}
int rank_k_subset(int *set, int n, int k)
{
int r = 0, i, j, a;
j = 0;
for (i = 0; i < n; i++) {
if (set[j] > i) {
a = binomial_coefficient(n - i - 1, k - j - 1);
r += a;
}
else {
j++;
}
if (j == k)
break;
}
202
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
return r;
}
void unrank_k_subset(int rk, int *set, int n, int k)
{
int r1, i, j, a;
j = 0;
for (i = 0; i < n; i++) {
a = binomial_coefficient(n - i - 1, k - j - 1);
if (rk >= a) {
rk -= a;
continue;
}
set[j] = i;
j++;
if (j == k)
break;
}
}
The 20 3-subsets of the 6-element set {0, 1, 2, 3, 4, 5} are (note that we have the same ordering as before!)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
0 : { 0 1 2 } : 0
1 : { 0 1 3 } : 1
2 : { 0 1 4 } : 2
3 : { 0 1 5 } : 3
4 : { 0 2 3 } : 4
5 : { 0 2 4 } : 5
6 : { 0 2 5 } : 6
7 : { 0 3 4 } : 7
8 : { 0 3 5 } : 8
9 : { 0 4 5 } : 9
10 : { 1 2 3 } : 10
11 : { 1 2 4 } : 11
12 : { 1 2 5 } : 12
13 : { 1 3 4 } : 13
14 : { 1 3 5 } : 14
15 : { 1 4 5 } : 15
16 : { 2 3 4 } : 16
17 : { 2 3 5 } : 17
18 : { 2 4 5 } : 18
19 : { 3 4 5 } : 19
3.19
Repeated Squaring and Multiplying
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// computes the k-th power of a modulo m
// using repeated squaring and multiplying
// Anton Betten 8/2007
#include <stdio.h>
int power_mod(int a, int n, int m);
/* computes a^n mod m */
int main(int argc, char **argv)
{
int a, k, m, b;
if (argc < 3) {
printf("usage %s <a> <k> <m>\n", argv[0]);
printf("computes the k-th power of a modulo m\n");
printf("using repeated squaring and multiplying\n");
}
203
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
sscanf(argv[argc - 3], "%d", &a);
sscanf(argv[argc - 2], "%d", &k);
sscanf(argv[argc - 1], "%d", &m);
b = power_mod(a, k, m);
printf("%d^%d mod %d
return 0;
= %d\n", a, k, m, b);
}
int power_mod(int a, int n, int m)
/* computes a^n mod m */
{
int b, c;
b = a;
c = 1;
while (n) {
if (n % 2) {
c = (b * c) % m;
}
b = (b * b) % m;
n >>= 1;
}
return c;
}
3.20
The Travelling Salesmen Problem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//
//
//
//
//
//
//
//
graph.h
Anton Betten
started:
4/22/2007
last change: 8/19/2007
#define TSP_COST_INFINITY 1000000
typedef class graph graph;
typedef class graph_node graph_node;
typedef class graph_edge graph_edge;
class graph {
public:
INT nb_nodes;
INT nb_nodes_allocated;
BYTE *label;
INT nb_edges;
INT nb_edges_allocated;
graph_node *N;
graph_edge *E;
INT *node_data1;
INT *node_data2;
INT *node_data3;
INT *edge_data1;
INT *edge_data2;
INT *edge_data3;
INT f_has_coordinates;
INT x_min, x_max, y_min, y_max;
204
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
graph();
void init(INT Nb_nodes, INT F_has_coordinates);
void induced_subgraph(INT nb_vertices, INT *vertex_subset, graph &H);
void random_subgraph(INT nb_vertices, graph &H);
void write_maple(BYTE *fname);
INT TSP(INT *tour);
void draw_tour(BYTE *fname, INT *tour);
void neighboring_tour(INT *tour, INT *new_tour, INT &i, INT &j, INT f_v);
INT is_permutation(INT *v, INT n);
INT cyclic_distance(INT i, INT j, INT n);
INT cost_of_tour(INT *tour);
INT find_edge(INT a, INT b);
INT spanning_tree(INT *edge_list, INT &s);
INT reduce_possible_edges(INT *edge_list, INT s);
INT cheapest_possible_edge(INT *possible_edges);
INT connected_component_if_tree(INT *edge_list, INT s, INT *component, INT &size);
void draw_network(BYTE *fname, INT xmax, INT ymax, INT *edges, INT nb_edges, INT f_vertex_lab
void print();
};
class graph_node {
public:
graph *G;
INT node_number;
BYTE *label;
INT weight1;
INT weight2;
INT x;
INT y;
};
class graph_edge {
public:
graph *G;
INT edge_number;
BYTE *label;
INT x, y; // coordinates for label;
BYTE *align; // align for label
INT
INT
INT
INT
node1; // "from" node if directed graph
node2; // "to" node if directed graph
weight1;
weight2;
};
//
//
//
//
//
//
//
//
network.c
Anton Betten
started:
4/22/2007
last change: 8/19/2007
#include <iostream>
#include <fstream>
#include <iomanip>
#include <stdio.h>
#include <stdlib.h> // for rand(), RAND_MAX
#include <math.h>
205
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using namespace std;
typedef long int INT;
typedef char BYTE;
#ifndef
#define
#endif
#ifndef
#define
#endif
TRUE
TRUE 1
FALSE
FALSE 0
#define MINIMUM(x, y)
( ((x) < (y)) ? (x) : (y) )
#define MAXIMUM(x, y)
( ((x) > (y)) ? (x) : (y) )
#define ABS(x)
( ((x) < 0 ) ? (-(x)) : (x) )
#include "graph.h"
#include "graphics.h"
#define MY_BUFSIZE 1000000
BYTE buf[MY_BUFSIZE];
void read_file(BYTE *fname_in, INT verbose_level, graph &G);
void chop_off_extension_if_present(char *p, char *ext);
void get_extension_if_present(char *p, char *ext);
void random_permutation(INT *random_permutation, INT n);
void perm_inverse(INT *a, INT *b, INT n);
INT random_integer(INT p);
void INT_vec_print(ostream &ost, INT *v, INT len);
void INT_vec_sort(INT len, INT *p);
INT file_size(BYTE *name);
void print_usage()
{
cout << "usage: network.out [options]\n";
cout << "where options can be:\n";
cout << "-v <n>
: verbose level <n>\n";
}
int main(int argc, char **argv)
{
BYTE str[1000];
BYTE ext[1000];
//BYTE *fname_in = "miles.dat";
BYTE *fname_in = "australia_miles.dat";
BYTE fname_out[1000];
INT i;
INT verbose_level = 0;
int t0, t1, dt;
t0 = time(0);
if (argc <= 1) {
print_usage();
exit(1);
}
for (i = 1; i < argc - 0; i++) {
if (strcmp(argv[i], "-v") == 0) {
verbose_level = atoi(argv[++i]);
cout << "-v " << verbose_level << endl;
}
}
graph G, H;
strcpy(str, fname_in);
get_extension_if_present(str, ext);
206
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
chop_off_extension_if_present(str, ext);
read_file(fname_in, verbose_level, G);
sprintf(fname_out, "%s", str);
G.draw_network(fname_out, 1500, 1200, NULL, 0, TRUE);
sprintf(fname_out, "%s_without", str);
G.draw_network(fname_out, 1500, 1200, NULL, 0, FALSE);
//G.random_subgraph(10, H);
//H.write_maple("network.maple.txt");
G.write_maple("network.maple.txt");
#if 0
INT subset[] = {0,8,42,25,30,12,3,38,37,51};
INT nb_vertices = 10;
INT Tour[] = {3,5,1,2,6,0,7,4,8,9};
G.induced_subgraph(nb_vertices, subset, H);
//H.write_maple("network.maple.txt");
//H.TSP(Tour);
#endif
//exit(1);
#if 0
INT j, e, a, b, deg;
//G.print();
INT *edge_list, s;
edge_list = new INT[G.nb_edges];
G.spanning_tree(edge_list, s);
cout << "found a spanning tree with " << s << " edges" << endl;
for (i = 0; i < s; i++) {
cout << edge_list[i] << " ";
}
cout << endl;
INT_vec_sort(s, edge_list);
for (i = 0; i < s; i++) {
cout << edge_list[i] << " ";
if (i) {
if (edge_list[i] == edge_list[i - 1])
cout << "repeated edge " << edge_list[i] << endl;
}
}
cout << endl;
for (i = 0; i < G.nb_nodes; i++) {
cout << "node " << i << " : " << G.N[i].label << " : ";
deg = 0;
for (j = 0; j < s; j++) {
e = edge_list[j];
a = G.E[e].node1;
b = G.E[e].node2;
if (i == a || i == b) {
cout << j << " ";
deg++;
}
}
cout << " degree " << deg << endl;
}
sprintf(fname_out, "%s_tree", str);
G.draw_network(fname_out, 1000, 800, edge_list, s, FALSE);
#endif
#if 1
207
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
INT *tour;
tour = new INT[G.nb_nodes];
random_permutation(tour, G.nb_nodes);
G.TSP(tour);
delete [] tour;
#endif
t1 = time(0);
/*printf("t0=%d\n", t0);
printf("t1=%d\n", t1);*/
dt = t1 - t0;
printf("this took %d seconds\n", dt);
return 0;
}
void read_file(BYTE *fname_in, INT verbose_level, graph &G)
{
INT l, i, dist;
cout << "opening file " << fname_in << " for reading" << endl;
ifstream f(fname_in);
//INT f_v = (verbose_level >= 1);
//INT f_vv = (verbose_level >= 2);
//INT f_vvv = (verbose_level >= 3);
BYTE *label, *xcoord, *ycoord, *population;
INT x, y, latitude, longitude, pop, a, b;
double f_latitude, f_longitude;
//G.init(128, TRUE);
G.init(55, TRUE);
G.f_has_coordinates = FALSE;
G.nb_nodes = 0;
G.nb_edges = 0;
while (TRUE) {
if (f.eof()) {
break;
}
//f.getline(buf, MY_BUFSIZE, ´\n´);
{
string S;
getline(f, S);
l = S.length();
cout << "read line of length " << l << " : " << S << endl;
for (i = 0; i < l; i++) {
buf[i] = S[i];
}
buf[l] = 0;
}
if (buf[0] == ´*´) {
if (strncmp(buf, "* End of file", 13) == 0) {
cout << "reached end of file" << endl;
break;
}
continue;
}
for (i = 0; i < l; i++)
if (buf[i] == ´[´)
break;
label = buf;
if (i == l) {
208
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
cout << "cound not find ´[´" << endl;
exit(1);
}
buf[i] = 0;
xcoord = buf + i + 1;
for (i++; i < l; i++)
if (buf[i] == ´,´)
break;
if (i == l) {
cout << "cound not find ´,´" << endl;
exit(1);
}
buf[i] = 0;
ycoord = buf + i + 1;
for (i++; i < l; i++)
if (buf[i] == ´]´)
break;
if (i == l) {
cout << "cound not find ´]´" << endl;
exit(1);
}
population = buf + i + 1;
sscanf(xcoord, "%lf", &f_latitude);
sscanf(ycoord, "%lf", &f_longitude);
//cout << "f_latitude = " << f_latitude << " f_longitude=" << f_longitude << endl;
a = (INT) f_latitude;
b = (INT) f_longitude;
f_latitude -= a;
f_longitude -= b;
//cout << "f_latitude minutes = " << f_latitude << " f_longitude minutes=" << f_longitude
f_latitude *= 100. / 60.;
f_longitude *= 100. / 60.;
latitude = 100 * a + (INT) f_latitude;
longitude = 100 * b + (INT) f_longitude;
x = longitude;
y = -latitude;
//latitude = atoi(xcoord);
//longitude = atoi(ycoord);
pop = atoi(population);
//x = -longitude;
//y = latitude;
G.N[G.nb_nodes].label = new BYTE[strlen(label) + 1];
strcpy(G.N[G.nb_nodes].label, label);
cout << "town " << G.nb_nodes << ": " << G.N[G.nb_nodes].label << " x=" << x << " y=" << y
G.N[G.nb_nodes].x = x;
G.N[G.nb_nodes].y = y;
G.N[G.nb_nodes].weight1 = pop;
if (G.f_has_coordinates) {
G.x_min = MINIMUM(G.x_min, x);
G.y_min = MINIMUM(G.y_min, y);
G.x_max = MAXIMUM(G.x_max, x);
G.y_max = MAXIMUM(G.y_max, y);
}
else {
G.f_has_coordinates = TRUE;
G.x_min = x;
G.x_max = x;
G.y_min = y;
G.y_max = y;
}
//cout << G.x_min << "," << G.y_min << "," << G.x_max << "," << G.y_max << endl;
#if 0
for (i = G.nb_nodes - 1; i >= 0; i--) {
f >> dist;
cout << dist << " ";
G.E[G.nb_edges].node1 = G.nb_nodes;
G.E[G.nb_edges].node2 = i;
209
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
G.E[G.nb_edges].weight1 = dist;
G.E[G.nb_edges].weight2 = 0;
G.nb_edges++;
}
cout << endl;
#else
for (i = 0; i < G.nb_nodes; i++) {
f >> dist;
cout << dist << " ";
G.E[G.nb_edges].node1 = G.nb_nodes;
G.E[G.nb_edges].node2 = i;
G.E[G.nb_edges].weight1 = dist;
G.E[G.nb_edges].weight2 = 0;
G.nb_edges++;
}
cout << endl;
#endif
if (G.nb_nodes) {
string S;
getline(f, S);
}
G.nb_nodes++;
}
cout << "found a graph with " << G.nb_nodes << " nodes and " << G.nb_edges << " edges" << end
}
void chop_off_extension_if_present(char *p, char *ext)
{
int l1 = strlen(p);
int l2 = strlen(ext);
if (l1 > l2 && strcmp(p + l1 - l2, ext) == 0) {
p[l1 - l2] = 0;
}
}
void get_extension_if_present(char *p, char *ext)
{
int i, l = strlen(p);
ext[0] = 0;
for (i = l - 1; i >= 0; i--) {
if (p[i] == ´.´) {
strcpy(ext, p + i);
}
}
}
void random_permutation(INT *random_permutation, INT n)
{
INT i, j, l, a;
INT *available_digits;
if (n == 0)
return;
if (n == 1) {
random_permutation[0] = 0;
return;
}
available_digits = new INT[n];
for (i = 0; i < n; i++) {
available_digits[i] = i;
}
l = n;
for (i = 0; i < n; i++) {
a = random_integer(l);
210
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
random_permutation[i] = available_digits[a];
for (j = a; j < l - 1; j++)
available_digits[j] = available_digits[j + 1];
l--;
}
delete [] available_digits;
}
void perm_inverse(INT *a, INT *b, INT n)
// b := a^-1
{
INT i, j;
for (i = 0; i < n; i++) {
j = a[i];
b[j] = i;
}
}
INT random_integer(INT p)
// computes a random integer r with $0 \le r < p.$
{
INT n;
if (p == 0) {
cout << "random_integer p = 0" << endl;
exit(1);
}
n = (INT)(((double)rand() * (double)p / RAND_MAX)) % p;
return n;
}
void INT_vec_print(ostream &ost, INT *v, INT len)
{
INT i;
ost << "( ";
for (i = 0; i < len; i++) {
ost << v[i];
if (i < len - 1)
ost << ", ";
}
ost << " )";
}
void INT_vec_sort(INT len, INT *p)
{
INT i, j, a;
for (i = 0; i < len; i++) {
for (j = i + 1; j < len; j++) {
if (p[i] > p[j]) {
a = p[i];
p[i] = p[j];
p[j] = a;
}
}
}
}
#include
#include
#include
#include
<cstdio>
<sys/types.h>
<unistd.h>
<fcntl.h>
INT file_size(BYTE *name)
{
INT handle, size;
211
432
433
434
435
436
437
438
439
440
441
442
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
handle = open(name, O_RDWR/*mode*/);
size = lseek(handle, 0L, SEEK_END);
close(handle);
return(size);
}
#include "graph.C"
#include "graphics.C"
// graph.C
//
// Anton Betten
//
// 4/22/2007
//
//
graph::graph()
{
label = NULL;
nb_nodes = 0;
nb_nodes_allocated = 0;
nb_edges = 0;
nb_edges_allocated = 0;
N = NULL;
E = NULL;
f_has_coordinates = FALSE;
}
void graph::init(INT Nb_nodes, INT F_has_coordinates)
{
INT i;
nb_nodes = 0;
nb_nodes_allocated = Nb_nodes;
nb_edges = 0;
nb_edges_allocated = Nb_nodes * Nb_nodes;
N = new graph_node[nb_nodes_allocated];
E = new graph_edge [nb_edges_allocated];
node_data1 = new INT [nb_nodes_allocated];
node_data2 = new INT [nb_nodes_allocated];
node_data3 = new INT [nb_nodes_allocated];
edge_data1 = new INT [nb_edges_allocated];
edge_data2 = new INT [nb_edges_allocated];
edge_data3 = new INT [nb_edges_allocated];
f_has_coordinates = F_has_coordinates;
for (i = 0; i < nb_nodes_allocated; i++) {
N[i].node_number = i;
}
for (i = 0; i < nb_edges_allocated; i++) {
E[i].edge_number = i;
}
}
void graph::induced_subgraph(INT nb_vertices, INT *vertex_subset, graph &H)
{
INT *perm_inv;
INT i, j, k, a, b;
perm_inv = new INT[nb_nodes];
for (i = 0; i < nb_nodes; i++) {
212
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
perm_inv[i] = -1;
}
for (i = 0; i < nb_vertices; i++) {
j = vertex_subset[i];
perm_inv[j] = i;
}
H.init(nb_vertices, f_has_coordinates);
H.nb_nodes = nb_vertices;
for (i = 0; i < nb_vertices; i++) {
j = vertex_subset[i];
H.N[i] = N[j];
}
H.nb_edges = 0;
for (i = 0; i < nb_vertices; i++) {
a = H.N[i].node_number;
for (j = 0; j < nb_vertices; j++) {
b = H.N[j].node_number;
k = find_edge(a, b);
if (k >= 0) {
H.E[H.nb_edges++] = E[k];
}
}
}
for (i = 0; i < nb_vertices; i++) {
H.N[i].node_number = i;
}
for (i = 0; i < H.nb_edges; i++) {
H.E[i].node1 = perm_inv[H.E[i].node1];
H.E[i].node2 = perm_inv[H.E[i].node2];
}
delete [] perm_inv;
}
void graph::random_subgraph(INT nb_vertices, graph &H)
{
INT *perm;
INT *perm_inv;
INT i, j, k, a, b;
perm = new INT[nb_nodes];
perm_inv = new INT[nb_nodes];
random_permutation(perm, nb_nodes);
perm_inverse(perm, perm_inv, nb_nodes);
H.init(nb_vertices, f_has_coordinates);
H.nb_nodes = nb_vertices;
for (i = 0; i < nb_vertices; i++) {
j = perm[i];
H.N[i] = N[j];
}
H.nb_edges = 0;
for (i = 0; i < nb_vertices; i++) {
a = H.N[i].node_number;
for (j = 0; j < nb_vertices; j++) {
b = H.N[j].node_number;
k = find_edge(a, b);
if (k >= 0) {
H.E[H.nb_edges++] = E[k];
}
}
}
for (i = 0; i < nb_vertices; i++) {
H.N[i].node_number = i;
}
for (i = 0; i < H.nb_edges; i++) {
H.E[i].node1 = perm_inv[H.E[i].node1];
H.E[i].node2 = perm_inv[H.E[i].node2];
}
delete [] perm;
213
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
delete [] perm_inv;
}
void graph::write_maple(BYTE *fname)
{
INT i;
ofstream f(fname);
f << "N := [" << nb_nodes << ", " << nb_edges << ",0,0];" << endl;
f << "N[3] := [";
for (i = 0; i < nb_nodes; i++) {
f << "[" << N[i].node_number + 1 << ","
<< "\"" << N[i].label << "\","
<< N[i].weight1 << ","
<< N[i].weight2 << ","
<< N[i].x << ","
<< N[i].y << "]";
if (i < nb_nodes - 1)
f << "," << endl;
}
f << "];" << endl;
f << "N[4] := [";
for (i = 0; i < nb_edges; i++) {
f << "[" << E[i].edge_number << ","
<< E[i].node1 + 1 << ","
<< E[i].node2 + 1 << ","
<< E[i].weight1 << ","
<< E[i].weight2 << ","
<< E[i].x << ","
<< E[i].y << "]";
if (i < nb_edges - 1)
f << "," << endl;
}
f << "];" << endl;
}
INT graph::TSP(INT *tour)
{
INT *new_tour, c1, c2, i, j, u, cnt = 0, cc, c1000, c1000_new, slide_cnt = 0;
BYTE fname[1000];
new_tour = node_data1;
is_permutation(tour, nb_nodes);
//random_permutation(tour, nb_nodes);
c1 = cost_of_tour(tour);
c1000 = c1 / 1000;
cout << "TSP starting, cost of initial tour " << c1 << endl;
while (TRUE) {
cnt++;
if ((cnt % 10000) == 0) {
cc = cnt / 10000;
sprintf(fname, "Tour_%ld", cc);
draw_tour(fname, tour);
slide_cnt++;
cout << "\\onlySlide*{" << slide_cnt << "}{%%PROSPER" << endl;
cout << "\\epsfig{file=" << fname << ".1,width=100mm}\\\\%%PROSPER" << endl;
cout << "{\\bf iteration " << cnt << " cost " << c1 << "}\\\\%%PROSPER" << endl;
cout << "}%%PROSPER" << endl;
cout << "\tmpost " << fname << ".mp
# %%MAKEFILE" << endl;
}
neighboring_tour(tour, new_tour, i, j, FALSE);
c2 = cost_of_tour(new_tour);
if (c2 < c1) {
for (u = 0; u < nb_nodes; u++) {
tour[u] = new_tour[u];
}
c1 = c2;
214
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
cout << "iteration " << cnt << " new cost of tour " << c1 << endl;
c1000_new = c1 / 1000;
if (c1000_new != c1000) {
sprintf(fname, "tour_%ld", c1000_new);
draw_tour(fname, tour);
c1000 = c1000_new;
slide_cnt++;
cout << "\\onlySlide*{" << slide_cnt << "}{%%PROSPER" << endl;
cout << "\\epsfig{file=" << fname << ".1,width=100mm}\\\\%%PROSPER" << endl;
cout << "{\\bf iteration " << cnt << " cost " << c1 << "}\\\\%%PROSPER" << endl;
cout << "}%%PROSPER" << endl;
cout << "\tmpost " << fname << ".mp
# %%MAKEFILE" << endl;
}
}
}
}
void graph::draw_tour(BYTE *fname, INT *tour)
{
INT *edge_list;
INT i, e, a, b;
edge_list = new INT[nb_nodes];
for (i = 0; i < nb_nodes; i++) {
a = tour[i];
b = tour[(i + 1) % nb_nodes];
e = find_edge(a, b);
edge_list[i] = e;
}
draw_network(fname, 1000, 800, edge_list, nb_nodes, FALSE);
delete [] edge_list;
}
void graph::neighboring_tour(INT *tour, INT *new_tour, INT &i, INT &j, INT f_v)
{
INT d, u, ip1, jp1, ii, jj;
i = random_integer(nb_nodes);
while (TRUE) {
j = random_integer(nb_nodes);
d = cyclic_distance(i, j, nb_nodes);
if (f_v) {
cout << "neighboring_tour i=" << i << ",j=" << j << " d=" << d << endl;
}
if (d > 1)
break;
}
for (u = 0; u < nb_nodes; u++) {
new_tour[u] = tour[u];
}
ip1 = (i + 1) % nb_nodes;
jp1 = (j + 1) % nb_nodes;
ii = ip1;
new_tour[ii] = tour[j];
new_tour[j] = tour[ii];
ii = (ii + 1) % nb_nodes;
jj = ((j - 1) + nb_nodes) % nb_nodes;
while (ii != j) {
new_tour[ii] = tour[jj];
ii = (ii + 1) % nb_nodes;
jj = ((jj - 1) + nb_nodes) % nb_nodes;
}
if (f_v) {
cout << "old: ";
INT_vec_print(cout, tour, nb_nodes);
cout << endl;
cout << "new: ";
INT_vec_print(cout, new_tour, nb_nodes);
cout << endl;
215
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
}
is_permutation(new_tour, nb_nodes);
}
INT graph::is_permutation(INT *v, INT n)
{
INT *w = new INT[n];
INT i;
for (i = 0; i < n; i++) {
w[i] = v[i];
}
INT_vec_sort(n, w);
for (i = 1; i < n; i++) {
if (w[i - 1] == w[i]) {
cout << "not a permutation" << endl;
exit(1);
}
}
delete [] w;
return TRUE;
}
INT graph::cyclic_distance(INT i, INT j, INT n)
{
INT d1, d2, d3, d4, d;
d1 = n + j - i;
d2 = n + i - j;
d3 = i - j;
d4 = j - i;
d1 = ABS(d1);
d2 = ABS(d2);
d3 = ABS(d3);
d4 = ABS(d4);
d = MINIMUM(d1, d2);
d = MINIMUM(d, d3);
d = MINIMUM(d, d4);
return d;
}
INT graph::cost_of_tour(INT *tour)
{
INT i, a, b, c, C, e;
C = 0;
for (i = 0; i < nb_nodes; i++) {
a = tour[i];
if (i == nb_nodes - 1) {
b = tour[0];
}
else {
b = tour[i + 1];
}
e = find_edge(a, b);
if (e == -1) {
c = TSP_COST_INFINITY;
}
else {
c = E[e].weight1;
}
C += c;
}
return C;
}
INT graph::find_edge(INT a, INT b)
{
INT i, c, d;
216
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
for (i = 0; i < nb_edges; i++) {
c = E[i].node1;
d = E[i].node2;
if ((a == c && b == d) || (a == d && b == c)) {
return i;
}
}
return -1;
}
INT graph::spanning_tree(INT *edge_list, INT &s)
{
INT i, idx, nb, a, b, slide_cnt = 0, cost = 0;
BYTE fname[1000];
s = 0;
for (i = 0; i < nb_edges; i++)
edge_data1[i] = FALSE;
for (i = 0; i < nb_edges; i++)
edge_data2[i] = TRUE;
while (s < nb_nodes - 1) {
idx = cheapest_possible_edge(edge_data2);
edge_data1[idx] = TRUE;
edge_data2[idx] = FALSE;
edge_list[s++] = idx;
cost += E[idx].weight1;
a = E[idx].node1;
b = E[idx].node2;
cout << s << " adding edge " << idx << " of distance " << E[idx].weight1 << " : " << a <<
nb = reduce_possible_edges(edge_list, s);
cout << "number of possible edges = " << nb << endl;
sprintf(fname, "tree_%ld", s);
draw_network(fname, 1000, 800, edge_list, s, FALSE);
slide_cnt++;
cout << "\\onlySlide*{" << slide_cnt << "}{%%PROSPER" << endl;
cout << "\\vspace*{-10mm}\\hspace*{-5mm}\\epsfig{file=" << fname << ".1,width=120mm}\\\\%%
cout << "{\\bf \\# edges " << s << " cost " << cost << "}\\\\%%PROSPER" << endl;
cout << "}%%PROSPER" << endl;
cout << "\tmpost " << fname << ".mp
# %%MAKEFILE" << endl;
if (nb == 0) {
return FALSE;
}
}
return TRUE;
}
INT graph::reduce_possible_edges(INT *edge_list, INT s)
{
INT i, size, nb = 0;
for (i = 0; i < nb_edges; i++) {
if (edge_data2[i]) {
edge_list[s] = i;
if (!connected_component_if_tree(edge_list, s + 1, node_data3, size)) {
edge_data2[i] = FALSE; // edge no longer possible
}
else {
nb++;
}
}
}
217
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
return nb;
}
INT graph::cheapest_possible_edge(INT *possible_edges)
{
INT i, c0, idx, c, f_first = TRUE;
for (i = 0; i < nb_edges; i++) {
if (!possible_edges[i])
continue;
if (f_first) {
c0 = E[i].weight1;
idx = i;
f_first = FALSE;
}
else {
c = E[i].weight1;
if (c < c0) {
c0 = c;
idx = i;
}
}
}
return idx;
}
INT graph::connected_component_if_tree(INT *edge_list, INT s, INT *component, INT &size)
{
INT i, j, u, e, a, b, c;
INT *my_edge_list;
my_edge_list = new INT[s];
for (i = 0; i < s; i++)
my_edge_list[i] = edge_list[i];
for (i = 0; i < nb_nodes; i++)
node_data1[i] = FALSE;
e = my_edge_list[s - 1];
s--;
a = E[e].node1;
b = E[e].node2;
node_data1[a] = TRUE;
node_data1[b] = TRUE;
component[0] = a;
component[1] = b;
size = 2;
for (i = 0; i < size; i++) {
c = component[i];
for (j = 0; j < s; j++) {
e = my_edge_list[j];
b = -1;
if (E[e].node1 == c) {
b = E[e].node2;
}
if (E[e].node2 == c) {
b = E[e].node1;
}
if (b >= 0) {
if (node_data1[b]) {
delete [] my_edge_list;
return FALSE;
}
node_data1[b] = TRUE;
component[size++] = b;
for (u = j; u < s - 1; u++) {
my_edge_list[u] = my_edge_list[u + 1];
}
j--;
s--;
218
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
}
}
}
delete [] my_edge_list;
return TRUE;
}
void graph::draw_network(BYTE *fname, INT xmax, INT ymax, INT *edges, INT nb_edges, INT f_vertex
{
mp_graphics G;
INT i, x, y, e, a, b;
INT rad = 5;
INT *Px;
INT *Py;
INT in[4], out[4];
Px = new INT[nb_nodes];
Py = new INT[nb_nodes];
G.setup(fname, xmax, ymax);
in[0]
in[1]
in[2]
in[3]
out[0]
out[1]
out[2]
out[3]
=
=
=
=
x_min;
y_min;
x_max;
y_max;
=
=
=
=
0;
0;
xmax;
ymax;
//cout << in[0] << "," << in[1] << "," << in[2] << "," << in[3] << endl;
//cout << out[0] << "," << out[1] << "," << out[2] << "," << out[3] << endl;
//draw_two_lines(G);
//draw_tangent_plane(G);
//draw_hyperbolic(G);
//draw_network(G);
//draw_network2(G);
for (i = 0; i < nb_nodes; i++) {
x = N[i].x;
y = N[i].y;
//cout << x << "," << y << " : ";
transform_llur(in, out, x, y);
Px[i] = x;
Py[i] = y;
//cout << x << "," << y << endl;
}
for (i = 0; i < nb_edges; i++) {
e = edges[i];
a = E[e].node1;
b = E[e].node2;
G.polygon2(Px, Py, a, b);
}
G.sf_interior(100);
G.sf_color(1);
for (i = 0; i < nb_nodes; i++) {
G.circle(Px[i], Py[i], rad);
if (f_vertex_labels) {
G.aligned_text(Px, Py, i, "tl", N[i].label);
}
}
G.finish(cout, TRUE);
delete [] Px;
delete [] Py;
}
219
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
void graph::print()
{
INT i, j, a, b, c;
for (i = 0; i < nb_nodes; i++) {
cout << "node " << i << " " << N[i].label << endl;
for (j = 0; j < nb_edges; j++) {
a = E[j].node1;
b = E[j].node2;
c = -1;
if (a == i) {
c = b;
}
if (b == i) {
c = a;
}
if (c >= 0) {
cout << "to " << c << " with edge " << j << " dist=" << E[j].weight1 << endl;
}
}
}
}
(the files graphics.c and graphics.h are not shown, as they are lengthy).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
Adelaide, SA[34.56,138.36]1
Albany, WA[34.57,117.54]1
2642
Albury, NSW[36.03,146.53]1
932 3570
Alice Springs, NT[23.42,133.52]1
1526 3558 2458
Ayers Rock/Yulara NT[25.18,131.18]1
1570 3602 2502 442
Bairnsdale VIC[37.51,147.38]1
1006 3648 310 2532 2574
Ballarat VIC[37.36,143.58]1
611 3253 372 2137 2181 395
Bathurst NSW[33.27,149.35]1
1183 3664 443 2548 2592 878 815
Bega NSW[36.41,149.50]1
1329 3810 426 2694 2738 326 721 468
Bendigo VIC[36.48,144.21]1
770 3251 297 2135 2179 432 121 740 709
Bordertown SA[36.18,140.49]1
267 2909 665 1793 1837 739 344 1093 1065 368
Bourke NSW[30.06,145.59]1
1129 3366 847 2250 2294 1157 995 574 965 874 1242
Brisbane QLD[27.30,153.00]1
2054 4291 1375 3004 3219 1691 1655 1004 1373 1534 1929 924
Broken Hill NSW[31.57,141.30]1
514 2751 866 1635 1679 1120 753 958 1292 697 781 615 1540
Broome WA[17.58,122.15]1
4242 2582 4905 2735 3177 5215 5436 5015 5406 4851 4509 4441 4659 4351
Bunbury WA[33.20,115.34]1
2855 361 3637 3771 3815 3861 3466 3877 4023 3464 3122 3579 4504 2964 2538
Cairns QLD[16.51,145.43]1
2964 5201 2650 2293 2735 2960 2830 2325 2723 2795 3160 1835 1701 2450 3948 5414
Canberra ACT[35.18,149.08]1
1153 3634 346 2518 2562 450 718 274 222 643 1011 743 1223 1080 5184 3847 2435
Carnarvon WA[24.51,113.45]1
3556 1292 4338 4128 4516 4562 4167 4578 4724 4165 3823 4280 5205 3665 1461 1069 5429 4548
Ceduna SA[32.07,133.42]1
769 1873 1551 1685 1729 1775 1380 1791 1937 1378 1036 1493 2418 878 3569 2086 3328 1761 2787
Charleville QLD[26.25,146.13]1
1583 3820 918 2332 2748 1611 1449 1028 1419 1328 1779 454 754 1069 3987 4033 1381 1197 4734 1947
Coober Pedy SA[28.56,134.45]1
220
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
837 2869 1619 689 733 1843 1448 1859 2005 1446 1104 1561 2486 946 3405 3082 2982 1829 3783 996 2
Darwin NT[12.23,130.44]1
3018 4375 3662 1492 1934 3972 4193 3772 4163 3627 3285 3198 3416 3127 1861 4183 2705 3941 3254 3
Dubbo NSW[32.16,148.41]1
1175 3503 531 2387 2431 841 882 206 604 761 1085 368 844 752 4809 3716 2119 382 4417 1630 822 16
Esperance WA[33.49,121.52]1
2168 474 3950 3084 3128 3174 2779 3190 3336 2777 2435 2892 3817 2277 912 687 4727 3160 1600 1399
Eucla WA[31.40,128.51]1
1256 1386 2038 2172 2216 2262 1867 2278 2424 1865 1523 1980 2905 1365 3082 1599 3815 2248 2300 4
Geraldton WA[28.49,114.36]1
3083 819 3865 3999 4040 4089 3694 4105 4251 3692 3350 3807 4732 3192 1934 596 5642 4075 473 2314
Grafton NSW[29.40,152.56]1
1815 4079 1162 2963 3007 1334 1522 735 1034 1401 1725 813 339 1328 4901 4292 2048 884 4993 2206
Horsham VIC[36.45,142.15]1
424 3066 508 1950 1994 582 187 951 908 211 157 1085 1745 609 4666 3279 3006 854 3980 1193 1539 1
Kalgoorlie/Boulder WA[30.49,121.29]1
2153 799 2935 3069 3113 3159 2764 3175 3321 2762 2420 2877 3802 2262 2185 764 4712 3145 1161 138
Katherine NT[14.29,132.20]1
2709 4066 3353 1183 1625 3663 3884 3463 3854 3318 2976 2889 3107 2818 1552 3874 2396 3632 2945 2
Kununurra WA[15.42,128.50]1
3202 3554 3865 1695 2137 4175 4396 3975 4366 3830 3488 3401 3619 3330 1040 3362 2908 4144 2433 3
Longreach QLD[23.30,144.15]1
2097 4334 1432 1818 2260 1671 1963 1542 1933 1842 2293 968 1186 1583 3473 4547 1053 1711 4954 24
Mackay QLD[21.10,149.10]1
2475 4712 2009 2396 2838 2319 2341 1684 2082 2220 2588 1346 980 1961 4051 7925 729 1860 5532 283
Meekatharra WA[26.30,118.30]1
2872 1116 3654 3788 3832 3837 3483 3894 4040 3481 3139 3596 4521 2981 1466 924 5344 3864 620 210
Melbourne VIC[37.45,144.58]1
723 3365 314 2249 2293 283 112 2355 609 149 456 989 1658 837 4965 3578 2933 660 4279 1492 1443 1
Mildura VIC[34.14,142.13]1
372 2849 571 1733 1777 821 454 811 957 398 411 877 1647 299 4490 3062 2749 781 3763 976 1368 104
Moree NSW[29.29,149.53]1
1548 3812 904 2696 2740 1214 1255 579 977 1134 1458 445 479 1061 4616 4025 1790 755 4726 1939 62
Mt Gambier SA[37.51,140.50]1
435 3077 677 1961 2005 695 305 1120 1026 426 183 1300 1960 870 4677 3290 3135 1023 3991 1204 175
Mt Isa QLD[20.50,139.29]1
2702 4734 2074 1176 1618 2313 2605 2184 2575 2484 2852 1610 1828 2225 2831 4947 1117 2353 4312 5
Newcastle NSW[32.55,151.46]1
1509 3884 693 2768 2812 865 1065 326 570 990 1358 749 818 1133 5099 4097 2339 415 4798 2011 1121
Perth WA[31.58,115.49]1
2689 406 3471 3605 3649 3695 3300 3711 3857 3295 2956 3413 4338 2798 2372 182 5248 3681 903 1920
Port Augusta SA[32.30,137.27]1
305 2337 1087 1221 1265 1311 916 1327 1473 914 572 1029 1954 414 3937 2550 2864 1297 3251 464 14
Port Hedland WA[20.24,118.36]1
3744 1988 4526 3349 3791 4750 4355 4766 4912 4353 4011 4468 5205 3853 614 1796 4543 4736 867 297
Port Lincoln SA[34.43,135.49]1
642 2277 1424 1558 1602 1648 1253 1664 1810 1251 909 1366 2291 751 3973 2490 3201 1634 3191 404
Renmark SA[34.10,140.35]1
247 2724 696 1608 1652 940 573 1714 1082 517 279 1039 1772 424 4324 2937 2874 906 3638 857 1493
Rockhampton QLD[23.22,150.32]1
2268 4505 3255 3389 3433 1986 2027 1351 1749 1906 2230 1139 647 1754 4154 4718 1062 1527 5419 26
Sydney NSW[33.55,151.10]1
1384 3865 562 2749 2793 734 934 201 418 859 1227 775 957 1159 5216 4078 2400 284 4779 1992 1229
Tamworth NSW[31.07,150.57]1
1510 3774 866 2658 2702 1129 1217 430 813 1096 1420 584 574 1023 4879 3987 2062 704 4688 1901 90
Tennant Creek NT[19.31,134.15]1
2040 4072 2736 514 956 2975 3267 2846 3237 2649 2307 2272 2490 2149 2221 4285 1779 3015 3614 219
Toowoomba QLD[27.35,151.54]1
1894 4158 1250 3042 3086 1560 1601 3148 1314 1480 1786 791 125 1407 4534 4371 1702 1205 5072 228
Townsville QLD[19.13,146.48]1
2617 4854 2303 2067 2509 2613 2483 1978 2420 2362 2813 1488 1376 2103 3722 5067 347 2088 5203 29
Wagga Wagga NSW[35.07,147.24]1
936 3417 125 2301 2345 435 497 318 393 422 790 722 1250 863 5017 3630 2525 244 4331 1544 1176 16
Warrnambool VIC[38.23,142.03]1
617 3259 544 2143 2187 513 171 986 839 292 365 1162 1826 850 4859 3472 3001 889 4173 1386 1621 9
West Wyalong NSW[33.54,147.12]1
919 3400 278 2284 2328 588 626 264 501 505 829 572 1100 846 5000 3613 2375 271 4314 1527 1026 15
* End of file
221
before optimization, a random tour:
the optimized tour:
222
Download