ACM11 Homework 1 Solutions

Contents

Problem 1: simple substitution cypher

Problem: decode the message. Below is how the message was encoded:

plainText = 'All work and no play makes Jack a dull boy';
k = 37;
cipherText = mod( plainText + k, 128 );

To recover it, using the fact that the original plain text contains the word "work", we can do the following (first, import the data into the variable "cipherText" and make sure "cipherText" is a row vector):

for kk = 1:128
    test = mod( cipherText - kk, 128 );
    if strfind(test,'work')
        recoveredText = test;
        disp(['At k = ',num2str(kk),' found the word ''work''']);
        break;
    end
end
disp('The recovered message is:');
disp( char(recoveredText) )
At k = 37 found the word 'work'
The recovered message is:
All work and no play makes Jack a dull boy

so we find that k = 37. A value of k = 91 is also acceptable, since perhaps it wasn't clear if we shifted UP by k or DOWN by k (and 91 = -37 modulo 128 ).

Problem 2 (original): vectorization

There were two versions of this, after we noticed different results on different computers and versions of MATLAB. Here's what the code should look like:

fprintf('On my computer, a 3 GHz Pentium 4 running Redhat linux,\n')
fprintf('  and with MATLAB version %s, the results are:\n',version);
randn('state',2008);
N  = 1e7;
a = randn(N,1); b = randn(N,1);
disp('... via my ''for'' loop:')
tic; s = 0;
for i = 1:N
    s = s + a(i)*b(i);
end
toc

disp('... via the command a''*b:')
tic
s2 = a'*b;
toc
disp(['Difference in answers is ',num2str(abs(s-s2)) ]);
disp('... and via command dot(a,b):');
tic
s3 = dot(a,b);
toc
On my computer, a 3 GHz Pentium 4 running Redhat linux,
  and with MATLAB version 7.2.0.294 (R2006a), the results are:
... via my 'for' loop:
Elapsed time is 16.660016 seconds.
... via the command a'*b:
Elapsed time is 0.036960 seconds.
Difference in answers is 0
... and via command dot(a,b):
Elapsed time is 0.165563 seconds.

Problem 2 (version 2): vectorization

Matrix multiplication in different ways. Using the "for" loop, there are several ways to do this. On the innermost loop, if you use a "for" loop for the third time, it probably will take minutes or hours to run, so I won't demonstrate that for a 500 x 500 matrix.

We will discuss in class the benefits of pre-allocating memory for a variable. Methods 1 and 2 below differ only in that the second method has already allocated space in RAM for the variable.

clear
randn('state',2008);
N  = 500;
B = randn(N); C = randn(N);
fprintf('On my computer, a 3 GHz Pentium 4 running Redhat linux,\n')
fprintf('  and with MATLAB version %s, the results are:\n',version);
disp('... method 1: via ''for'' loop, without pre-allocating memory:')
tic
for i = 1:N
    for j = 1:N
        A(i,j) = B(i,:) * C(:,j);
    end
end
toc

disp('... method 2: via ''for'' loop, with pre-allocating memory:')
tic
A2 = zeros(N);  % pre-allocate space for the variable
for i = 1:N
    for j = 1:N
        A2(i,j) = B(i,:) * C(:,j);
    end
end
toc
% Method 3: really slow!
% tic
% A3 = zeros(N);
% for i = 1:N
%     for j = 1:N
%         for k = 1:N
%             A3(i,j) = A3(i,j) + B(i,k) * C(k,j);
%         end
%     end
% end
% toc
disp('... method 4: using MATLAB''s builtin command:');
% Method 4: matlab's version
tic
A4 = B*C;
toc
fprintf('And the value of A(1,1) is %.6f\n',A(1,1) );
On my computer, a 3 GHz Pentium 4 running Redhat linux,
  and with MATLAB version 7.2.0.294 (R2006a), the results are:
... method 1: via 'for' loop, without pre-allocating memory:
Elapsed time is 6.156748 seconds.
... method 2: via 'for' loop, with pre-allocating memory:
Elapsed time is 5.010969 seconds.
... method 4: using MATLAB's builtin command:
Elapsed time is 0.317947 seconds.
And the value of A(1,1) is 0.734259

Problem 3

This shows how functions behave differently depending on the input. The function "diag", with with a matrix input, returns a vector, and if given a vector input, returns a matrix.

The simplest answer is B = diag(diag(A)); for example:

A = randn(5)
B = diag(diag(A))
A =

   -0.9762    0.6231    0.7027    1.9495   -0.8712
    0.3872    0.8008   -0.5929   -0.7131   -0.7103
   -1.8757   -0.3361   -0.6677    0.9442    0.0630
   -0.6952   -0.0010    1.8529    0.5051    0.0511
   -2.0533    0.0425    1.0980    0.3940   -0.2299


B =

   -0.9762         0         0         0         0
         0    0.8008         0         0         0
         0         0   -0.6677         0         0
         0         0         0    0.5051         0
         0         0         0         0   -0.2299

Problem 4: Solving linear systems (accuracy)

We find that none of the methods do a great job finding "x", and only the builtin linear solver does well at finding a vector xhat that gives a small residual.

N = 11;
A = hilb(N);
x = ones(N,1);
b = A*x;
% Solve, method 1:
xhat1 = A\b;
% xhat1 = linsolve(A,b)  % is very similar
fprintf('Error, via method 1, is %.2e\n', norm(xhat1-x) );
fprintf('Residual, via method 1, is %.2e\n\n', norm(A*xhat1-b) );

% Solve, method 2:
xhat2 = inv(A) * b;
fprintf('Error, via method 2, is %.2e\n', norm(xhat2-x) );
fprintf('Residual, via method 2, is %.2e\n\n', norm(A*xhat2-b) );

% Solve, method 3:
xhat3 = invhilb(N) * b;
fprintf('Error, via method 3, is %.2e\n', norm(xhat3-x) );
fprintf('Residual, via method 3, is %.2e\n\n', norm(A*xhat3-b) );

fprintf('Actual x \t xhat1 \t xhat2 \t xhat3\n')
[x, xhat1, xhat2, xhat3]
Error, via method 1, is 1.05e-02
Residual, via method 1, is 5.98e-16

Error, via method 2, is 2.46e-02
Residual, via method 2, is 8.18e-04

Error, via method 3, is 3.33e-02
Residual, via method 3, is 4.79e-03

Actual x 	 xhat1 	 xhat2 	 xhat3

ans =

    1.0000    1.0000    1.0000    1.0000
    1.0000    1.0000    1.0000    1.0000
    1.0000    1.0000    1.0000    1.0000
    1.0000    1.0001    1.0003    1.0001
    1.0000    0.9994    1.0021    0.9976
    1.0000    1.0022    0.9993    1.0088
    1.0000    0.9951    0.9814    0.9844
    1.0000    1.0066    1.0127    1.0273
    1.0000    0.9945    1.0000    0.9961
    1.0000    1.0025    1.0098    1.0044
    1.0000    0.9995    0.9999    0.9990

Problem 5: Solving linear systems (time)

Here's what a small Hadamard matrix looks like:

hadamard(8)
ans =

     1     1     1     1     1     1     1     1
     1    -1     1    -1     1    -1     1    -1
     1     1    -1    -1     1     1    -1    -1
     1    -1    -1     1     1    -1    -1     1
     1     1     1     1    -1    -1    -1    -1
     1    -1     1    -1    -1     1    -1     1
     1     1    -1    -1    -1    -1     1     1
     1    -1    -1     1    -1     1     1    -1

This matrix is well-conditioned ( you can check with "cond( )" ). For both methods, we get no error (to within machine precision).

N = 2048;
A = hadamard(N);
x = ones(N,1);
b = A*x;
clc
% Solve, method 1:
tic;xhat = A\b;toc
fprintf('Error, via method 1, is %f\n', norm(xhat-x) );
fprintf('Residual, via method 1, is %f\n\n', norm(A*xhat-b) );

% Solve, method 2:
tic;xhat = inv(A) * b;toc
fprintf('Error, via method 2, is %f\n', norm(xhat-x) );
fprintf('Residual, via method 2, is %f\n\n', norm(A*xhat-b) );
Elapsed time is 0.900489 seconds.
Error, via method 1, is 0.000000
Residual, via method 1, is 0.000000

Elapsed time is 2.195640 seconds.
Error, via method 2, is 0.000000
Residual, via method 2, is 0.000000