Making a function sensitive for vector input - matlab

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!

Related

Implementing a Function using for-loops and matrix multiplication in matlab

My goal is to implement a function which performs fourier synthesis in matlab, as part of learning the language. The function implements the following expression:
y = sum(ak*exp((i*2*pi*k*t)/T)
where k is the index, ak is a vector of fourier coefficients, t is a time vector of sampled times, and T is the period of the signal.
I have tried something like this:
for counter = -N:1:N
k = y+N+1;
y(k) = ak(k)*exp((i*2*pi*k*t)/T);
% y is a vector of length 2N+1
end
However, this gives me an error that the sides do not have equal numbers of items within them. This makes sense to me, since t is a vector of arbitrary length, and thus I am trying to make y(k) equal to numerous things rather than one thing. Instead, I suspect I need to try something like:
for counter = -N:1:N
k=y+N+1;
for t = 0:1/fs:1
%sum over t elements for exponential operation
end
%sum over k elements to generate y(k)
end
However, I'm supposedly able to implement this using purely matrix multiplication. How could I do this? I've tried to wrap my head around what Matlab is doing, but honestly, it's so far from the other languages I know that I don't really have any sense of what matlab's doing under the hood. Understanding how to change between operations on matrices and operations in for loops would be profoundly helpful.
You can use kron to reach your goal without for loops, i.e., matrix representation:
y = a*exp(1j*2*pi*kron(k.',t)/T);
where a,k and t are all assumed as row-vectors
Example
N = 3;
k = -N:N;
t = 1:0.5:5;
T = 15;
a = 1:2*N+1;
y = a*exp(1j*2*pi*kron(k.',t)/T);
such that
y =
Columns 1 through 6:
19.1335 + 9.4924i 10.4721 + 10.6861i 2.0447 + 8.9911i -4.0000 + 5.1962i -6.4721 + 0.7265i -5.4611 - 2.8856i
Columns 7 through 9:
-2.1893 - 4.5489i 1.5279 - 3.9757i 4.0000 - 1.7321i

MATLAB Simple Calculation

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

Row--wise application of an inline function

I defined an inline function f that takes as argument a (1,3) vector
a = [3;0.5;1];
b = 3 ;
f = #(x) x*a+b ;
Suppose I have a matrix X of size (N,3). If I want to apply f to each row of X, I can simply write :
f(X)
I verified that f(X) is a (N,1) vector such that f(X)(i) = f(X(i,:)).
Now, if I a add a quadratic term :
f = #(x) x*A*x' + x*a + b ;
the command f(X) raises an error :
Error using +
Matrix dimensions must agree.
Error in #(x) x*A*x' + x*a + b
I guess Matlab is considering the whole matrix X as the input to f. So it does not create a vector with each row, i, being equal to f(X(i,:)). How can I do it ?
I found out that there exist a built-in function rowfun that could help me, but it seems to be available only in versions r2016 (I have version r2015a)
That is correct, and expected.
MATLAB tries to stay close to mathematical notation, and what you are doing (X*A*X' for A 3×3 and X N×3) is valid math, but not quite what you intend to do -- you'll end up with a N×N matrix, which you cannot add to the N×1 matrix x*a.
The workaround is simple, but ugly:
f_vect = #(x) sum( (x*A).*x, 2 ) + x*a + b;
Now, unless your N is enormous, and you have to do this billions of times every minute of every day, the performance of this is more than acceptable.
Iff however this really and truly is your program's bottleneck, than I'd suggest taking a look at MMX on the File Exchange. Together with permute(), this will allow you to use those fast BLAS/MKL operations to do this calculation, speeding it up a notch.
Note that bsxfun isn't going to work here, because that does not support mtimes() (matrix multiplication).
You can also upgrade to MATLAB R2016b, which will have built-in implicit dimension expansion, presumably also for mtimes() -- but better check, not sure about that one.

MATLAB: For loop structure [duplicate]

This question already has answers here:
Element-wise array replication in Matlab
(7 answers)
Closed 6 years ago.
This is a basic program but since I'm new to MATLAB, I'm not able to figure out the solution.
I have a column vector "Time" in which I want to print value "1" in first 147 cells, followed by "2" in 148 to 2*147 cells and so on. For that, I have written the following script:
Trial>> c=1;
Trial>> k=0;
Trial>> for i = c:146+c
Time(i,1)=1+k;
c=i;
k=k+1;
end
I know I need to iterate the loop over "Time(i,1)=1+k;" before it executes the next statement. I tried using break but that's not supposed to work. Can anyone suggest me the solution to get the desired results?(It was quite simple in C with just the use of curly braces.)
I am sure you don't want to run c=i; in every iteration.
My code should work for you:
x = 10; % Replace 10 by the max number you need in your array.
k = 1;
for i = 1 : x * 147
Time(i, 1) = k;
if rem(i, 147) == 0
k = k + 1;
end
end
This is the prime example of a piece of code that should be vectorized can help you understand vectorization. Your code can be written like this:
n = 147;
reps = 10; %% Replace this by the maximum number you want your matrix to have
Time = reshape(bsxfun(#plus, zeros(n,1), 0:reps), 1, []);
Explanation:
Let A be a column vector (1 column, n rows), and B be a row vector (1 row, m columns.
What bsxfun(#plus, A, B) will do here is to add all elements in A with all elements in B, like this:
A(1)+B(1) A(1)+B(2) A(1)+B(3) ... A(1)+B(m)
A(2)+B(1) A(2)+B(2) ............. A(2)+B(m)
............................................
A(n)+B(1) A(n)+B(2) .............. A(n)+B(m)
Now, for the two vectors we have: zeros(n,1), and 0:reps, this will give us;
0+0 0+1 0+2 0+reps
0+0 0+1 0+2 0+reps
% n rows of this
So, what we need to do now is place each column underneath each other, so that you will have the column with zeros first, then the row with ones, ... and finally the one with reps (147 in your case).
This can be achieved by reshaping the matrix:
reshape(bsxfun(#plus, zeros(n,1), 0:reps), [], 1);
^ ^ ^ ^
| | | Number of rows in the new matrix. When [] is used, the appropriate value will be chosen by Matlab
| | Number of rows in the new matrix
| matrix to reshape
reshape command
Another approach is using kron:
kron(ones(reps+1, 1) * 0:(n-1)
For the record, a review of your code:
You should always preallocate memory for matrices that are created inside loops. In this case you know it will become a matrix of dimensions ((reps+1)*n-by-1). This means you should do Time = zeros((reps+1)*n, 1);. This will speed up your code a lot.
You shouldn't use i and j as variable names in Matlab, as they denote the imaginary unit (sqrt(-1)). You can for instance do: for ii = 1:(n*147) instead.
You don't want c=i inside the loop, when the loop is supposed to go from c to c + 146. That doesn't make much sense.
You can use repmat,
x = 10; % Sequence length (or what ever it can be called)
M = repmat(1:x,147,1); % Replicate array 1:x for 147 columns
M = M(:); % Reshape the matrix so that is becomes a column vector.
I can assume that this is a task to practice for loops, but this will work.
An alternative solution may be to do
n = 147;
reps = 10;
a = ceil( (1:(n*reps)) / n);
You first construct an array with the length you want. Then you divide, and round of upwards. 1 to 147 will then become 1.

Matlab programming dealing with matrix

I am trying out one of the matlab programming question.
Question:
Write a function called hulk that takes a row vector v as an input and
returns a matrix H whose first column consist of the elements of v,
whose second column consists of the squares of the elements of v, and
whose third column consists of the cubes of the elements v. For
example, if you call the function likes this, A = hulk(1:3) , then A
will be [ 1 1 1; 2 4 8; 3 9 27 ].
My Code:
function H = hulk(v)
H = [v; v.^2; v.^3];
size(H) = (n,3);
end
When I test my code using A = hulk(1:3), it throws an error on console.
Your function made an error for argument(s) 0
Am I doing something incorrect? Have I missed anything?
Remove the line size(H) = (n,3);
and add the line H = H';
Final code should be as follows
function H = hulk(v)
H = [v; v.^2; v.^3];
H = H';
end
Your code giving error in matlab editor on the size(H) = (n,3); line
That's why you should use the matlabeditor itself
For your future reference, you can very easily generalise this function in Matlab to allow the user to specify the number of cols in your output matrix. I also recommend that you make this function a bit more defensive by ensuring that you are working with column vectors even if your user submits a row vector.
function H = hulk(v, n)
%//Set default value for n to be 3 so it performs like your current function does when called with the same signature (i.e. only 1 argument)
if nargin < 2 %// nargin stands for "Number of ARGuments IN"
n = 3;
end if
%// Next force v to be a row vector using this trick (:)
%// Lastly use the very useful bsxfun function to perform the power calcs
H = bsxfun(#power, v(:), 1:n);
end
You could reduce the number of operations using cumprod. That way, each v.^k is computed as the previous v.^k times v:
function H = hulk(v, n)
H = cumprod(repmat(v,n,1),1);
The first input argument is the vector, and the second is the maximum exponent.