Vectorising a function array in Matlab - matlab

My generic problem is illustrated by the following example:
f=#(x,y) cos(x.*y);
Yvalues = linspace(0,1,50);
W = #(x) f(x,Yvalues);
which works fine if I only want to evaluate W at one point at a time. For instance:
norm(W(pi/3)-f(pi/3,Yvalues))
ans =
0
But how do I go about evaluating W at any number of points?
Thanks in advance.

If you change
f=#(x,y) cos(x.*y);
to
f=#(x,y) cos(x'*y);
you can execute
W([1 2 3])
For example,
>> f = #(x,y) cos(x'*y);
>> yv = linspace(0,1,5);
>> W = #(x) f(x,yv);
>> W(1)
ans =
1.0000 0.9689 0.8776 0.7317 0.5403
>> W(2)
ans =
1.0000 0.8776 0.5403 0.0707 -0.4161
>> W(3)
ans =
1.0000 0.7317 0.0707 -0.6282 -0.9900
>> W([1 2 3])
ans =
1.0000 0.9689 0.8776 0.7317 0.5403
1.0000 0.8776 0.5403 0.0707 -0.4161
1.0000 0.7317 0.0707 -0.6282 -0.9900

Related

Linear regression (regress) discrepancy with polynomial fit (polyfit)

I have some data which comes from a linear function (y=mx+c) where m=4, c=1 (so: y=4x+1).
When I try to get back the coefficients using regress, I'm getting an R2<1 and a seemingly random m value:
x = [1 2 3 4]
y = [5 9 13 17]
[m,bint,r,rint,stats] = regress(y',x');
%{
>> R = stats(1) % Coefficient of determination
R =
1
>> m % Linear function coefficients
m =
4.333333333333333
%}
Whereas polyfit does this correctly:
P = polyfit(x,y,1);
%{
>> P(1)
ans =
4.000000000000000
>> P(2)
ans =
1.000000000000000
%}
Why is this happening?
The source of your problem is not following the documentation or regress which states that:
b = regress(y,X) returns a vector b of coefficient estimates for a multiple linear regression of the responses in vector y on the predictors in matrix X. The matrix X must include a column of ones.
If we include a column of ones in the 2nd input, we get the desired result:
x = [1 2 3 4].';
y = [5 9 13 17].';
[m,bint,r,rint,stats] = regress(y,[ones(size(x)) x]);
%{
Results:
m =
1.0000
4.0000
bint =
1.0000 1.0000
4.0000 4.0000
r =
1.0e-14 *
0.1776
0.1776
0.1776
0
rint =
1.0e-13 *
0.0178 0.0178
-0.2190 0.2545
-0.2190 0.2545
-0.2141 0.2141
stats =
1.0e+31 *
0.0000 1.6902 0.0000 0.0000
%}

Create vectors associated with each entry of an array and save them in a new matrix

Say i have a matrix like A = [1 2; 3 4], and that i need to create 4, vectors each one associated to one entrance of the matrix, such that the first one goes from -1..1, and second from -2..2, and so forth. Wath i try was
for j=1:2
for k=1:2
W=linspace(-A(j,k),A(j,k),4)
end
end
the problem with that line is that it not save the data.
Also i need that to create a new matrix, such that every row be one of the vectors that i mentioned.
I know that on octave i can do
W=linspace(-A,A,4)
but in MATLAB it doesn't work
If you want 4 values evenly distributed between A(k) and A(k), then you can use an anonymous function in combination with linspace this way:
fun = #(x) linspace(-A(x), A(x), 4)
b = fun(1:numel(A))
b =
-1.00000 -0.33333 0.33333 1.00000
-3.00000 -1.00000 1.00000 3.00000
-2.00000 -0.66667 0.66667 2.00000
-4.00000 -1.33333 1.33333 4.00000
Assuming you want [-1 0 1], [-2 -1 0 1 2] etc, then I suggest using arrayfun like this:
A = [1 2;3 4];
b = arrayfun(#(n) -A(n):A(n), 1:numel(A), 'UniformOutput',0)
b =
{
[1,1] =
-1 0 1
[1,2] =
-3 -2 -1 0 1 2 3
[1,3] =
-2 -1 0 1 2
[1,4] =
-4 -3 -2 -1 0 1 2 3 4
Your approach didn't work because you're overwriting W everytime you loop. The following works:
V = zeros(numel(A),4);
for k=1:numel(A)
W(k,:) = linspace(-A(k),A(k),4);
end
The reason why I only use one index for A is because you may use linear indexing in MATLAB. Remember to allocate memory before you assign values to a matrix inside a loop. "Growing" matrices are very slow.
You can do it like that
W = zeros(4,4);
a = reshape(A, 1, 4);
for i=1:4
W(i,:) = linspace(-a(i), a(i), 4);
end
and you obtain
W =
-1.0000 -0.3333 0.3333 1.0000
-3.0000 -1.0000 1.0000 3.0000
-2.0000 -0.6667 0.6667 2.0000
-4.0000 -1.3333 1.3333 4.0000
If you want to generate a fixed number of values (say 4) for each entry of A, you can achieve it in one line:
>> bsxfun(#times, linspace(-1,1,4), A(:))
ans =
-1.0000 -0.3333 0.3333 1.0000
-3.0000 -1.0000 1.0000 3.0000
-2.0000 -0.6667 0.6667 2.0000
-4.0000 -1.3333 1.3333 4.0000

matlab equality check going wrong. decides true on an arbitrary moment

THE CODE:
function[E] = eig_noshift(A)
A_k = A;
for(i=0:inf)
[Qk,Rk] = qr(A_k);
A_k1 = Rk*Qk;
diag(A_k1)
diag(A_k)
isequal(diag(A_k1),diag(A_k))
if(isequal(diag(A_k1),diag(A_k)))
break
end
A_k = A_k1;
end
E = diag(A_k);
I'm creating a matlab method that calculates a matrix' eigenvalues with the QR-algorithm. (which works) i'm trying to break the for loop if the next matrix diagonal is equal to the current diagonal (algorithm has converged)
When executing the algorithm I get following output:
>> eig_noshift(A0)
Warning: FOR loop index is too large. Truncating to 281474976710655.
> In eig_noshift at 3
ans =
4.8419
1.2591
-0.0011
ans =
-22.2000
-14.6000
42.9000
ans =
0
ans =
4.9434
1.0611
0.0954
ans =
4.8419
1.2591
-0.0011
ans =
0
ans =
4.9881
1.0123
0.0996
ans =
4.9434
1.0611
0.0954
ans =
0
ans =
4.9976
1.0024
0.1000
ans =
4.9881
1.0123
0.0996
ans =
0
ans =
4.9995
1.0005
0.1000
ans =
4.9976
1.0024
0.1000
ans =
0
ans =
4.9999
1.0001
0.1000
ans =
4.9995
1.0005
0.1000
ans =
0
ans =
5.0000
1.0000
0.1000
ans =
4.9999
1.0001
0.1000
ans =
0
ans =
5.0000
1.0000
0.1000
ans =
5.0000
1.0000
0.1000
ans =
0
ans =
5.0000
1.0000
0.1000
ans =
5.0000
1.0000
0.1000
ans =
0
--- a few dozen more iterations that are the same ---
ans =
5.0000
1.0000
0.1000
ans =
5.0000
1.0000
0.1000
ans =
0
ans =
5.0000
1.0000
0.1000
ans =
5.0000
1.0000
0.1000
ans =
1
The 0/1 values are as you can see the truth value of checking the equality between the previous 2 vectors outputted. As you can see, the algo should have converged/stopped a long while ago, but didn't until some arbetrary moment. What am I doing wrong?
SOLUTION:
ofcourse I forgot to put matlab in format long and didn't think about it straight on. (I don't use matlab all that often) anyway the solution I have is adding a precision boundary to the method, resulting in following code:
function[E] = eig_noshift(A, prec)
A_k = A;
v_prec = [prec;prec;prec];
for(i=0:inf)
[Qk,Rk] = qr(A_k);
A_k1 = Rk*Qk;
if(diag(A_k1) - diag(A_k) < v_prec)
break
end
A_k = A_k1;
end
E = diag(A_k);
Method stops when asked precision has been reached. cheers!
The output does not include all digits. Print the difference instead: diag(A_k1)-diag(A_k)

How to solve an equation vectorwise?

Is there any vectorwise equation solver in matlab?
For example if I have a vector a = [1 8 27] then solving x.^3-a=0 will give us [1 2 3]
Thanks!
Try fminsearch:
>> x = fminsearch( #(x) sum( ( x.^3 - a ).^2 ), [0 0 0] )
x =
1.0000 2.0000 3.0000
This can be done with the solve command.
The good news is that it is quite easy to use and rather powerfull.
Unfortunately you do need the symbolic toolbox to use this.
Here is an example:
syms a b c x
solve(a*x^2 + b*x + c == 0)
If you don't have the symbolic toolbox you wont be able to run this.
You can combine arrayfun and fzero to achieve this:
>> arrayfun(#(a) fzero(#(x) x^3-a,0), [1 8 27])
ans =
1.0000 2.0000 3.0000

Make a general import of upper triangular matrix in MATLAB

I have been trying to make a general import of Ghaul's answer to my earlier question about importing an upper triangular matrix.
Initial Data:
1.0 3.32 -7.23
1.00 0.60
1.00
A = importdata('A.txt')
A =
1.0000 3.3200 -7.2300
1.0000 0.6000 NaN
1.0000 NaN NaN
So you will have to shift the two last rows, like this:
A(2,:) = circshift(A(2,:),[0 1])
A(3,:) = circshift(A(3,:),[0 2])
A =
1.0000 3.3200 -7.2300
NaN 1.0000 0.6000
NaN NaN 1.0000
and then replace the NaNs with their symmetric counterparts:
A(isnan(A)) = A(isnan(A)')
A =
1.0000 3.3200 -7.2300
3.3200 1.0000 0.6000
-7.2300 0.6000 1.0000
I have this, so we get the complete matrix for any size:
A = importdata('A.txt')
for i = (1:size(A)-1)
A(i+1,:) = circshift(A(i+1,:),[0 i]);
end
A(isnan(A)) = A(isnan(A)');
Is this approach the best? There must be something better. I remember someone told me to try not to use for loops in MATLAB.
UPDATE
So this is the result. Is there any way to make it faster without the loop?
A = importdata('A.txt')
for i = (1:size(A)-1)
A(i+1,:) = circshift(A(i+1,:),[0 i])
end
A(isnan(A)) = 0;
A = A + triu(A, 1)';
Here's another general solution that should work for any size upper triangular matrix. It uses the functions ROT90, SPDIAGS, and TRIU:
>> A = [1 3.32 -7.23; 1 0.6 nan; 1 nan nan]; %# Sample matrix
>> A = spdiags(rot90(A),1-size(A,2):0); %# Shift the rows
>> A = A+triu(A,1).' %'# Mirror around the main diagonal
A =
1.0000 3.3200 -7.2300
3.3200 1.0000 0.6000
-7.2300 0.6000 1.0000
Here's one way without loop. If you have a more recent version of Matlab, you may want to check which solution is really faster, since loops aren't as bad as they used to be.
A = A'; %'# transpose so that linear indices get the right order
out = tril(ones(size(A))); %# create an array of indices
out(out>0) = A(~isnan(A)); %# overwrite the indices with the right number
out = out + triu(out',1); %'# fix the upper half of the array