Can someone help me debug this Matlab code? Like I have a matrix A, and I need to find A^k by diagonalization method. Below is my original code, but there is a problem with this part:
m = (M - R(i,1)*eye(NumRowsR));
disp(rref(m));
t = null(rref(m));
disp(t);
This part can't give me the nullspace of matrix t after reduced for some reasons (I recently did some research on the Internet and see some people said about the bug of rref and null). The problem is that it keeps showing me elementary matrix
1 0 0
0 1 0
0 0 1
for the eigenvalues. Does anyone know how to fix it? I will be very much appreciated!
Below is my original code, for a better view:
syms x NumRowsM NumColsM NumRowsR NumColsR NumRowst NumColst k numeigen
M = input('Input a square matrix M: ');
k = input('Input the power of matrix M: ');
[NumRowsM, NumColsM]=size(M);
if (NumRowsM ~= NumColsM)
disp('Not valid input. Matrix must be a square matrix!')
else
%Find eigenvalues:
R = solve(det(M - x*eye(NumRowsM)), x);
[NumRowsR, NumColsR] = size(R);
if (or(NumRowsR == 0,NumColsR == 0))
disp('No eigenvalues. The matrix is not diagonalizable')
else
numeigen = 0;
F = zeros(NumRowsR, NumRowsR);
d = zeros(NumRowsR,1);
for i = 1:NumRowsR
m = (M - R(i,1)*eye(NumRowsR));
disp(rref(m));
t = null(rref(m));
disp(t);
[NumRowst, NumColst] = size(t);
if (NumColst == 0)
if (i == NumRowsR && numeigen > NumRowsR)
disp('Matrix not diagonalizable due to invalid eigenvalue');
return
else
continue
end
else
numeigen = numeigen + 1;
if (NumColst == 1)
for j = 1:NumRowsR
[n, d(j)] = numden(sym(t(j,1)));
end
for j = 1:NumRowsR
F(j,i) = sym(t(j,1)) * lcm(sym(d));
end
else
for k = 1:NumColst
for j = 1:NumRowsR
[n, d(j)] = numden(sym(t(j,k)));
end
for j = 1:NumRowsR
F(j,k) = sym(t(j,k)) * lcm(sym(d));
end
end
end
end
end
disp(F);
D = (F\M)*F;
disp('The power k of the matrix M is: ');
T = F*(D^k)/(F);
disp(T)
end
end
This is my first script in matlab. ( I cannot use functions)
Let's say I have a vector of time instants
t = [0:999]*1e-5; %vector of time instants
And my function is m
This is the part where it is implemented:
if (t >= 0)
if t <= to/3
m = 1;
elseif (t <= 2*to/3)
m = -2;
end
else
m = 0;
end
As I realised, m has only one value equal to 1.
How is this possible to have a 1x1000 value here? Where for values of t from 0 to to/3 -> m = 1, to/3 to 2*to/3 -> m = -2and else m=0
You can apply a function on each element of an array using arrayfun like the following:
arrayfun(#(x) m(x), t)
%or
arrayfun(#m, t)
You can find the details here. Also, you can implement your function like the following:
function result = m(t)
result = t;
result(t >= 0 && t <= to/3) = 1;
result(t > to/3 && t <= 2*to/3) = -2;
result(t < 0) = 0;
then call the function m on t such as m(t).
I have a matrix named l having size 20X3.
What I wanted to do was this :
Suppose I have this limits:
l1_max=20; l1_min=0.5;
l2_max=20; l2_min=0.5;
mu_max=20; mu_min=0.5;
I wanted to force all the elements of the matrix l within the limits.
The values of 1st column within l1_max & l1_min.
The values of 2nd column within l2_max & l2_min.
The values of 3rd column within mu_max & mu_min.
What I did was like this:
for k=1:20
if l(k,1)>l1_max
l(k,1) = l1_max;
elseif l(k,1)<l1_min
l(k,1) = l1_min;
end
if l(k,2)>l2_max
l(k,2) = l2_max;
elseif l(k,2)<l2_min
l(k,2) = l2_min;
end
if l(k,3)>mu_max
l(k,3) = mu_max;
elseif l(k,3)<mu_min
l(k,3) = mu_min;
end
end
Can it be done in a better way ?
You don't have to loop over rows, use vectorized operations on entire columns:
l(l(:, 1) > l1_max, 1) = l1_max;
l(l(:, 1) < l1_min, 1) = l1_min;
Similarily:
l(l(:, 2) > l2_max, 2) = l2_max;
l(l(:, 2) < l2_min, 2) = l2_min;
l(l(:, 3) > l2_max, 3) = mu_max;
l(l(:, 3) < l2_min, 3) = mu_min;
An alternative method, which resembles to Bas' idea, is to apply min and max as follows:
l(:, 1) = max(min(l(:, 1), l1_max), l1_min);
l(:, 2) = max(min(l(:, 2), l2_max), l2_min);
l(:, 3) = max(min(l(:, 3), mu_max), mu_min);
It appears that both approaches have comparable performance.
You don't even have to loop over all columns, the operation on the whole matrix can be done in 2 calls to bsxfun, independent of the number of columns:
column_max = [l1_max, l2_max, mu_max];
column_min = [l1_min, l2_min, mu_min];
M = bsxfun(#min, M, column_max); %clip to maximum
M = bsxfun(#max, M, column_min); %clip to minimum
This uses two tricks: to clip a value between min_val and max_val, you can do clipped_x = min(max(x, min_val), max_val). The other trick is to use the somewhat obscure bsxfun, which applies a function after doing singleton expansion. When you use it on two matrices, it 'extrudes' the smallest one to the same size as the largest one before applying the function, so the example above is equivalent to M = min(M, repmat(column_max, size(M, 1), 1)), but hopefully calculated in a more efficient way.
Below is a benchmark to test the various methods discussed so far. I'm using the TIMEIT function found on the File Exchange.
function [t,v] = testClampColumns()
% data and limits ranges for each column
r = 10000; c = 500;
M = randn(r,c);
mn = -1.1 * ones(1,c);
mx = +1.1 * ones(1,c);
% functions
f = { ...
#() clamp1(M,mn,mx) ;
#() clamp2(M,mn,mx) ;
#() clamp3(M,mn,mx) ;
#() clamp4(M,mn,mx) ;
#() clamp5(M,mn,mx) ;
};
% timeit and check results
t = cellfun(#timeit, f, 'UniformOutput',true);
v = cellfun(#feval, f, 'UniformOutput',false);
assert(isequal(v{:}))
end
Given the following implementations:
1) loop over all values and compare against min/max
function M = clamp1(M, mn, mx)
for j=1:size(M,2)
for i=1:size(M,1)
if M(i,j) > mx(j)
M(i,j) = mx(j);
elseif M(i,j) < mn(j)
M(i,j) = mn(j);
end
end
end
end
2) compare each column against min/max
function M = clamp2(M, mn, mx)
for j=1:size(M,2)
M(M(:,j) < mn(j), j) = mn(j);
M(M(:,j) > mx(j), j) = mx(j);
end
end
3) truncate each columns to limits
function M = clamp3(M, mn, mx)
for j=1:size(M,2)
M(:,j) = min(max(M(:,j), mn(j)), mx(j));
end
end
4) vectorized version of truncation in (3)
function M = clamp4(M, mn, mx)
M = bsxfun(#min, bsxfun(#max, M, mn), mx);
end
5) absolute value comparison: -a < x < a <==> |x| < a
(Note: this is not applicable to your case, since it requires a symmetric limits range. I only included this for completeness. Besides it turns out to be the slowest method.)
function M = clamp5(M, mn, mx)
assert(isequal(-mn,mx), 'Only works when -mn==mx')
idx = bsxfun(#gt, abs(M), mx);
v = bsxfun(#times, sign(M), mx);
M(idx) = v(idx);
end
The timing I get on my machine with an input matrix of size 10000x500:
>> t = testClampColumns
t =
0.2424
0.1267
0.0569
0.0409
0.2868
I would say that all the above methods are acceptably fast enough, with the bsxfun solution being the fastest :)
I have the following error in MATLAB:
??? Subscript indices must either be real positive integers or
logicals.
Error in ==> Lloyd_Max at 74 D(w_count) = mean((x -
centers(xq)).^2);
This is my code :
function [ xq,centers,D ] = Lloyd_Max( x,N,min_value,max_value )
%LLOYD_MAX Summary of this function goes here
% Detailed explanation goes here
x = x';
temp = (max_value - min_value)/2^N;
count=1;
for j=0:temp:((max_value - min_value)-temp),
centers(count) = (j + j + temp )/2;
count = count + 1;
end
for i=1:length(centers),
k(i) = centers(i);
end
w_count = 0;
while((w_count < 2) || (D(w_count) - D(w_count - 1) > 1e-6))
w_count = w_count + 1;
count1 = 2;
for i=2:(count-1),
T(i) = (k(i-1) + k(i))/2;
count1 = count1 +1 ;
end
T(1) = min_value;
T(count1) = max_value;
index = 1;
for j=2:count1,
tempc = 0;
tempk = 0;
for k=1:10000,
if(x(k) >= T(j-1) && x(k) < T(j))
tempk = tempk + x(k);
tempc = tempc + 1;
end
end
k(index) = tempk;
k_count(index) = tempc;
index = index + 1;
end
for i=1:length(k),
k(i) = k(i)/k_count(i);
end
for i=1:10000,
if (x(i) > max_value)
xq(i) = max_value;
elseif (x(i) < min_value)
xq(i) = min_value;
else
xq(i) = x(i);
end
end
for i=1:10000,
cnt = 1;
for l=2:count1,
if(xq(i) > T(l-1) && xq(i) <= T(l))
xq(i) = cnt;
end
cnt = cnt +1 ;
end
end
D(w_count) = mean((x - centers(xq)).^2);
end
end
and i call it and have these inputs :
M = 10000
t=(randn(M,1)+sqrt(-1)*randn(M,1))./sqrt(2);
A= abs(t).^2;
[xq,centers,D] = Lloyd_Max( A,2,0,4 );
I tried to comment the while and the D, Results :
I got the xq and the centers all normal, xq in the 1-4 range, centers 1-4 indexes and 0.5-3.5 range.
I dont know whats going wrong here...Please help me.
Thank in advance!
MYSTERY SOVLED!
Thank you all guys for your help!
I just putted out of the while the for loop :
for i=1:10000,
if (x(i) > max_value)
xq(i) = max_value;
elseif (x(i) < min_value)
xq(i) = min_value;
else
xq(i) = x(i);
end
end
and it worked like charm.... this loop was initilizing the array again. Sorry for that. Thank you again!
There is an assignment xq(i) = x(i) somewhere in the middle of your function, but you pass A as x from outside where you calculate A from t which is sampled by randn, so you can't promise xq is an integer.
I'm not sure exactly what you are aiming to do, but your vector xq does not contain integers, it contains doubles. If you want to use a vector of indices as you do with centers(xq), all elements of the vector need to be integers.
Upon a little inspection, it looks like xq are x values, you should find some way to map them to the integer of the closest cell to which they belong (i'm guessing 'centers' represents centers of cells?)
I am very new in Matlab. I made a for loop with i to m ,and j to n. I wrote this code to take a submatrix of a matrix but it keeps giving me this error
Subscript indices must either be real positive integers or logicals.
this is the code
for i=1:m,
for j = 1:n,
display(i);
display(j);
edgeil = 2;
edgeib = 2;
edgejb = 2;
edgejl = 2;
if((i-CenteriSE)< 0)
edgeib = CenteriSE - (-1)*(i-CenteriSE);
end
if((i+ CenteriSE)> m)
temp = i+ CenteriSE - m;
edgeil = CenteriSE - temp;
end
if((j-CenterjSE)< 0)
edgejb = CenterjSE- (-1)*(j-CenterjSE);
end
if((j+ CenterjSE)> n)
temp2 = j+ CenterjSE - n;
edgejl = CenterjSE - temp2;
end
bok1 = round(edgeib);
bok2 = round(edgeil);
bok3 = round(edgejb);
bok4 = round(edgejl);
display(bok1);
display(bok2);
if( (bok1 == round(bok1)) && (bok2 == round(bok2)) && (bok3 == round(bok3)) && (bok4 == round(bok4)))
B = circles(i-round(bok1):i+round(bok2),j-round(bok3):j+round(bok4));
end
I wrote that if statement and round s to correct it but it doesnt work. Please help me how can I fix this?
well, it's simple. first let's just remove all the clutter. you say CenteriSE=2, so this statement
edgeib = CenteriSE - (-1)*(i-CenteriSE); is equivalent to edgeib=i for i=1.
Now if you go to your last statement, B = circles(i-round(bok1):i+round(bok2),j-round(bok3):j+round(bok4));, you're doing i-round(bok1), which is just i-i=0 when i=1. Matlab's indexing start from 1, and this is why you get this error.