I am working on MATLAB on my own, and was doing problem 9 on Project Euler
It states
" A Pythagorean triplet is a set of three natural numbers, a < b < c, for which,
a2 + b2 = c2
For example, 32 + 42 = 9 + 16 = 25 = 52.
There exists exactly one Pythagorean triplet for which a + b + c = 1000.
Find the product abc."
Below is the code I wrote; however, it compiles, but does not produce and output. I was hoping to get some feedback on what's wrong, so I can fix it.
Thanks,
syms a;
syms b;
syms c;
d= 1000;
d= a + b + c ;
ab= a.^2 + b.^2;
ab= c.^2;
c
I propose a vectorized way (that is, without using loops) to solve the problem. It may seem relatively complicated, especially if you come from other programming languages; but for Matlab you should get used to this way of approaching problems.
Ingredients:
Vectorization;
Indexing;
Transpose;
Implicit singleton expansion;
hypot;
find.
Read up on these concepts if you are not familiar with them, and then try to solve the problem yourself (which of course is the whole point of Project Euler). As a hint, the code below proceeds along these lines:
Generate a 1×1000 vector containing all possible values for a and b.
Compute a 1000×1000 matrix with the values of c corresponding to each pair a, b
From that compute a new matrix such that each entry contains a+b+c
Find the row and column indices where that matrix equals 1000. Those indices are the desired a and b (why?).
You'll get more than one solution (why?). Pick one.
Compute the product of the obtained a and b and the corresponding c.
Once you have tried yourself, you may want to check the code (move the mouse over it):
ab = 1:1000; % step 1
cc = hypot(ab,ab.'); % step 2
sum_abc = ab+ab.'+cc; % step 3
[a, b] = find(sum_abc==1000); % step 4
a = a(1); b = b(1); % step 5
prod_abc = a*b*cc(a,b); % step 6
Related
Here is the problem and current code I am using.
Use the svd() function in MATLAB to compute , the rank-2 approximation of . Clearly state what is, rounded to 4 decimal places. Also, compute the root-mean square error (RMSE) between and . Which approximation is better, or ? Explain.
Solution:
%code
[U , S, V] = svd(A)
k = 2
V = V(:,1:k)
V = transpose(V)
Ak = U(:,1:k) .* S(1:k,1:k) .* V
diffA = A - A2
fro_norm = norm(diffA,'fro')
RMSE2 = (fro_norm)/sqrt(m*n)
However, when running, the line AK = . . . keeps giving an error because the matrix sizes are not compatible. So I understand that the matrix sizes need to match in order to do the multiplication, but I also know that the problem requires the following calculation requirements, that when k = 2, U has to use the first 2 columns, S has to use the first 2 rows and first 2 columns, and V has to be the transpose of V only using the first two columns.
I must be missing something in my understanding of the calculation, or creation of the sub k matrices. The matrix I have to use is a 3 x 3.
In an attempt to speed up for loops (or eliminate all together), I've been trying to pass matrices into functions. I have to use sine and cosine as well. However, when I attempt to find the integral of a matrix where the elements are composed of sines and cosines, it doesn't work and I can't seem to find a way to make it do so.
I have a matrix SI that is composed of sines and cosines with respect to a variable that I have defined using the Symbolic Math Toolbox. As such, it would actually be even better if I could just pass the SI matrix and receive a matrix of values that is the integral of the sine/cosine function at every location in this matrix. I would essentially get a square matrix back. I am not sure if I phrased that very well, but I have the following code below that I have started with.
I = [1 2; 3 4];
J = [5 6; 7 8];
syms o;
j = o*J;
SI = sin(I + j);
%SI(1,1) = sin(5*o + 1)
integral(#(o) o.*SI(1,1), 0,1);
Ideally, I would want to solve integral(#(o) o*SI,0,1) and get a matrix of values. What should I do here?
Given that A, B and C are all N x N matrices, for the moment, let's assume they're all 2 x 2 matrices to make the example I'm illustrating more succinct to understand. Let's also define o as a mathematical symbol based on your comments in your question above.
syms o;
A = [1 2; 3 4];
B = [5 6; 7 8];
C = [9 10; 11 12];
Let's also define your function f according to your comments:
f = o*sin(A + o*B + C)
We thus get:
f =
[ o*sin(5*o + 10), o*sin(6*o + 12)]
[ o*sin(7*o + 14), o*sin(8*o + 16)]
Remember, for each element in f, we take the corresponding elements in A, B and C and add them together. As such, for the first row and first column of each matrix, we have 1, 5 and 9. As such, A + o*B + C for the first row, first column equates to: 1 + 5*o + 9 = 5*o + 10.
Now if you want to integrate, just use the int command. This will find the exact integral, provided that the integral can be solvable in closed form. int also can handle matrices so it will integrate each element in the matrix. You can call it like so:
out = int(f,a,b);
This will integrate f for each element from the lower bound a to the upper bound b. As such, supposing our limits were from 0 to 1 as you said. Therefore:
out = int(f,0,1);
We thus get:
out =
[ sin(15)/25 - sin(10)/25 - cos(15)/5, sin(18)/36 - sin(12)/36 - cos(18)/6]
[ sin(21)/49 - sin(14)/49 - cos(21)/7, sin(24)/64 - sin(16)/64 - cos(24)/8]
Bear in mind that out is defined in the symbolic math toolbox. If you want the actual numerical values, you need to cast the answer to double. Therefore:
finalOut = double(out);
We thus get:
finalOut =
0.1997 -0.1160
0.0751 -0.0627
Obviously, this can generalize for any size M x N matrices, so long as they all share the same dimensions.
Caveat
sin, cos, tan and the other related functions have their units in radians. If you wish for the degrees equivalent, append a d at the end of the function (i.e. sind, cosd, tand, etc.)
I believe this is the answer you're after. Good luck!
I need to create a polynomial of the form:
P(x) = q(1,1) + q(2,2)(x-z(1)) + q(3,3)(x-z(1))(x-z(2)) + --- + q(2n, 2n)(x-z(1))(x-z(2))...(x-z(2n)) NOTE: The indices of the equation have been shifted to accomodate MATLAB.
in MATLAB. Consult this link here specifically slides 15 and 16.
I have the matrix Q filled, so I have the diagonal, and I also have z(1:2n) filled.
I'm having a hard time figuring out a way to create a polynomial that I can graph this polynomial. I've tried to use a for loop to append each term to P(x), but it doesn't operate the way I thought it would.
So far, my code will calculate the coefficients (presented as Q(0,0) -> Q(2n+1, 2n+1) in the problem above) without a problem.
I'm having an issue with the construction of a degree n polynomial of the form described above. Plotting makes more sense now, create a vector x with evaluative values, and then run them through the polynomial "function" and plot the x vector against the resulting vector.
So I just need to create this polynomial.
I would use diag and cumprod to help you accomplish this. First use diag to extract the diagonals of your matrix Q. After, use cumprod to generate a vector of cumulative products.
How cumprod works on a vector is that for each element in the vector, the i'th element collects products from 1 up to the i'th element. As an example, if we had a vector V = [1 2 3 4 5], cumprod(V) would produce [1 2 6 24 120]. The 4th element (as an example) would be 1*2*3*4, representing the products from the 1st to the 4th element.
As such, this is the code that I would do:
qdiag = diag(Q);
xMinusZ = x - z; % Takes z and does x - z for every element in z
cumProdRes = cumprod(xMinusZ);
P = sum(qdiag .* [1;cumProdRes(1:end-1)]);
P should give you P(x) that you desired. Make sure that z is a column vector to make it compatible with the diagonals extracted from Q.
NB: I believe there is a typo in your equation. The last term of your equation (going with your convention) should have (x-z(2n-1)) and not (x-z(2n)). This is because the first term in your equation does not have z.
Here's an example. Let's suppose Q is defined
Q = [1 2 3 4; 5 6 7 8; 9 10 11 12; 13 14 15 16];
The vector z is:
z = [4;3;2;1];
Let's evaluate the function at x = 2
Extracting the diagonals of Q should give us Q = [1;6;11;16]. Subtract x from every element of z should give us:
xMinusZ = [-2;-1;0;1];
Using the equation that you have above, we have:
P = 1 + 6*(-2) + 11*(-2)*(-1) + 16*(-2)*(-1)*(0) = 11
This is what the code should give.
What if we want to do this for more than one value of x?
As you have stated in your post, you want to evaluate this for a series of x values. As such, you need to modify the code so that it looks like this (make sure that x is a column vector):
qdiag = diag(Q);
xMinusZ = repmat(x,1,length(z)) - repmat(z',length(z),1);
cumProdRes = cumprod(xMinusZ,2);
P = sum(repmat(qdiag',length(z),1).*[ones(length(z),1) cumProdRes(:,1:end-1)],2);
P should now give you a vector of outputs, and so if you want to plot this, simply do plot(x,P);
This is for my course in numerical methods. I am trying very hard to understand MATLAB and its syntax but I am 100% self-taught, so please bear with me if my attempts seem ridiculous.
I have written this very easy function to approximate the number e
function e= calcEulerLimit(n)
e = (1 + 1./n).^n;
end
This is the 'basic' definition of the number e using a limit n to infinity approach. For MATLAB I defined the following vector (when I am talking about n in the latter, I am always referring to this vector n)
n=[1:1:10]=[ 1 2 3 4 5 6 7 8 9 10 ]
and the output works just fine as I expected, it is sensitive towards the vector n input when I call my function in MATLAB.
>> calcEulerlimit(n)
ans =
2.0000 2.2500 2.3704 2.4414 2.4883 2.5216 2.5465 2.5658 2.5812 2.5937
Now I want to do the exact same as above with a Taylor Approach, using the infinite summation formula to describe e, here is where I am stuck, the following simple code works:
function e = calcEulerSum(n)
e=1; % base-case, start variable
for i=1:1:n % for loop with step size one
e=e+1/factorial(i)
end
end
but this input, of course, does not work when I want to enter a vector such as n that computes through all variables.
I tried something along the line with another for loop, and a while loop, but the while loop seems to never terminate:
function e = calcEulerSum3(n)
while n
e=1;
e = e + 1./cumprod(n);
end
end
Using cumprod(n) to get the factorial value of each column element of my vector n.
You're trying to vectorize your function. Your solution for scalars works so let's look at what it's doing as i is incremented:
e0 = 1;
i = 1: e(1) = e0 + 1/factorial(1)
i = 2: e(2) = e(1) + 1/factorial(2) = e0 + 1/factorial(1) + 1/factorial(2)
= e0 + sum(1./factorial(1:2))
i = 3: e(3) = e(2) + 1/factorial(3) = ...
= e0 + sum(1./factorial(1:3))
...
i = n: e(n) = e(n-1) + 1/factorial(n) = e0 + 1/factorial(1) + ... + 1/factorial(n)
= e0 + sum(1./factorial(1:n))
So can you come up with a general expression to calculate the vector e given n? The cumsum function will come in handy.
for i=whatsoever,statement(i);end executes the statement on every element of whatsoever. If it is a single number, then on this one, if it is a vector/array, then on every element of it.
1:1:n creates an array of integers from 1 to n on the spot (1:n would do, too). If n already is a vector with the elements you want to iterate over, you can use it directly: for i=n.
However, why did you use the dotted versions of operations in your first and third code block, but not your second? Because you read about MATLAB's vectorization? Then you seem to be on the right track, but remember that the point vectorization is to get rid of an explicit loop entirely.
function e = calcEulerSum(n)
e=nan(1,length(n)); % initialize to nan
for j=1:length(n) % for each element in the input
e(j)=sum(1./factorial(0:n(j))); %each entry is computed in this step, one at a time
end
In this code, each approximation has been vectorized, but I don't see an easy way to vectorize the entire program. There is also no error checking, like making sure the elements of n are non-negative integers, or that n is a vector and not an array.
In the original example, the while never terminates because n never changes.
This should be enough to help get you started.
Cheers!
I'm desperately trying to avoid a for loop in Matlab, but I cannot figure out how to do it. Here's the situation:
I have two m x n matrices A and B and two vectors v and w of length d. I want to outer multiply A and v so that I get an m x n x d matrix where the (i,j,k) entry is A_(i,j) * v_k, and similarly for B and w.
Afterward, I want to add the resulting m x n x d matrices, and then take the mean along the last dimension to get back an m x n matrix.
I'm pretty sure I could handle the latter part, but the first part has me completely stuck. I tried using bsxfun to no avail. Anyone know an efficient way to do this? Thanks very much!
EDIT: This revision comes after the three great answers below. gnovice has the best answer to the question I asked without a doubt. However,the question that I meant to ask involves squaring each entry before taking the mean. I forgot to mention this part originally. Given this annoyance, both of the other answers work well, but the clever trick of doing algebra before coding doesn't help this time. Thanks for the help, everyone!
EDIT:
Even though the problem in the question has been updated, an algebraic approach can still be used to simplify matters. You still don't have to bother with 3-D matrices. Your result is just going to be this:
output = mean(v.^2).*A.^2 + 2.*mean(v.*w).*A.*B + mean(w.^2).*B.^2;
If your matrices and vectors are large, this solution will give you much better performance due to the reduced amount of memory required as compared to solutions using BSXFUN or REPMAT.
Explanation:
Assuming M is the m-by-n-by-d matrix that you get as a result before taking the mean along the third dimension, this is what a span along the third dimension will contain:
M(i,j,:) = A(i,j).*v + B(i,j).*w;
In other words, the vector v scaled by A(i,j) plus the vector w scaled by B(i,j). And this is what you get when you apply an element-wise squaring:
M(i,j,:).^2 = (A(i,j).*v + B(i,j).*w).^2;
= (A(i,j).*v).^2 + ...
2.*A(i,j).*B(i,j).*v.*w + ...
(B(i,j).*w).^2;
Now, when you take the mean across the third dimension, the result for each element output(i,j) will be the following:
output(i,j) = mean(M(i,j,:).^2);
= mean((A(i,j).*v).^2 + ...
2.*A(i,j).*B(i,j).*v.*w + ...
(B(i,j).*w).^2);
= sum((A(i,j).*v).^2 + ...
2.*A(i,j).*B(i,j).*v.*w + ...
(B(i,j).*w).^2)/d;
= sum((A(i,j).*v).^2)/d + ...
sum(2.*A(i,j).*B(i,j).*v.*w)/d + ...
sum((B(i,j).*w).^2)/d;
= A(i,j).^2.*mean(v.^2) + ...
2.*A(i,j).*B(i,j).*mean(v.*w) + ...
B(i,j).^2.*mean(w.^2);
Try reshaping the vectors v and w to be 1 x 1 x d:
mean (bsxfun(#times, A, reshape(v, 1, 1, [])) ...
+ bsxfun(#times, B, reshape(w, 1, 1, [])), 3)
Here I am using [] in the argument to reshape to tell it to fill that dimension in based on the product of all the other dimensions and the total number of elements in the vector.
Use repmat to tile the matrix in the third dimension.
A =
1 2 3
4 5 6
>> repmat(A, [1 1 10])
ans(:,:,1) =
1 2 3
4 5 6
ans(:,:,2) =
1 2 3
4 5 6
etc.
You still don't have to resort to any explicit loops or indirect looping using bsxfun et al. for your updated requirements. You can achieve what you want by a simple vectorized solution as follows
output = reshape(mean((v(:)*A(:)'+w(:)*B(:)').^2),size(A));
Since OP only says that v and w are vectors of length d, the above solution should work for both row and column vectors. If they are known to be column vectors, v(:) can be replaced by v and likewise for w.
You can check if this matches Lambdageek's answer (modified to square the terms) as follows
outputLG = mean ((bsxfun(#times, A, reshape(v, 1, 1, [])) ...
+ bsxfun(#times, B, reshape(w, 1, 1, []))).^2, 3);
isequal(output,outputLG)
ans =
1