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