Matrix index out of range during loop - matlab

a is an nxn matrix.
I have this code:
[m,n] = size(a);
x = zeros(m,1);
for j=1:1:n
if(j==1)
a(1,:) = [];
else
end
disp(a);
a(:,j) = [];
disp(x);
disp(a);
end
And it gives error on the line a(:,j) = []; which says
Matrix index is out of range for deletion.
Why? I dont understand, help appreciated.

Instead of:
for j=1:1:n
Try using:
for j=n:-1:1
What's going on is you're deleting columns starting from j=1 and therefore shortening your matrix each time. As soon as j is greater than the remaining number of columns in a, it will throw that error.
Iterating backwards as I am suggesting will solve this problem (because your index is decreasing at the same time as your matrix size is decreasing).

Related

Print/Store each row in matrix - MATLAB

I have a 150 X 4 matrix and I wish to loop through the matrix length and print each of the rows out.
This is my attempted code:
X = xlsread('filename.csv');
J = X(:, [2:5]) % extracting rows 2 to 5 into a matrix
for i= 0:length(J)
Y = J(i,:); %loop through each row and store it in Y
end;
But I keep getting the following error:
Subscript indices must either be real positive integers or logicals.
Is my approach incorrect? What am I missing out here? I simply want to loop through each row and store it in a variable.
In MATLAB the indices start at 1 and not at 0, so you should do:
for i= 1:length(J)
Y = J(i,:); %loop through each row and store it in Y
end;
In addition, regarding the following line that you wrote:
J = X(:, [2:5]) % extracting rows 2 to 5 into a matrix
Note that you actually stored in J columns 2,3,4,5, of X and not rows 2,3,4,5.

Filling in a Cell of Matrices in MATLAB

In Matlab I am trying to create a cell of size 16 x1 where each entry of this cell is a matrix. I have the following equation
$$W_g = exp^{\frac{j{2\pi m}{N}(n+\frac{g}{G}))} \,\,\,\,\,\,\, m,n=0,1,.....(N-1)$$
for this work assume $N=4$ and the index $g$ is the index that refers to the cell element i.e g=0:1:15
W=cell(16,1);
for g=1:16
for m=1:3
for n=1:3
W{g,m,n}= exp((2*pi*j*m/4)* n+(g-1)/16));
end
end
end
How can I make this work? I have two problems with this, you see g starts from 0 and MATLAB doesnt accept index of zero and how to actually define the matrices within the cell.
Thanks
So if I understand you have this equation:
And you just want the following code:
W=cell(16,1);
n = 1:3;
m = 1:3;
N = 4;
for g=1:16
W{g}= exp((2*pi*j.*m/4*N).*n+(g-1)/16);
end
%or the 1 line version:
W = cellfun(#(g) exp((2*pi*j.*m/4*N).*n+(g-1)/16),num2cell([1:16]),'UniformOutput',0);
With matlab you can use the Element-wise multiplication symbol .*
For example:
%A matrix multiplication
A = [2,3]
B = [1,3]';
result = A * B %result = 11
%An element wise multiplication
A = [2,3]
B = [1,3];
result = A .* B %result = [2,9]
First of all, i is the complex number in matlab (sqrt(-1)) not j, and you are correct, matlab is indexed in 1, so simply start counting g at 1, until 16.
Next, create a zero matrix, and calculate all indices accordingly. Something like this should work just fine :
clc
clear all
W=cell(16,1);
for g=1:16;
temp = zeros(3,3);
for m=1:3
for n=1:3
temp (m,n) = exp((2*pi*1i*m/4)* n+g/16);
end
end
W{g} = temp;
end
if you are considering doing much larger operations, consider using linspace to create your m and n indices and using matrix operations

Putting a matrix in to sparse form in linear time using matlab

I'm trying to put a matrix in sparse form, and so far I'm looping through the rows and columns checking every element to see if it's non zero. However, this seems to be order n^2, where n is the number of non zero elements in the matrix. Is there a way to do this order n?
Here is my code
function a = inputMatrix(X)
[m,n] = size(X);
k=1;
for i=1:m
for j=1:n
if X(i,j)~=0
X(i,j);
a(1,k) = struct('row',i,'column',j,'data',X(i,j));
k = k+1;
end
end
end
Here is my time testing
ri = zeros(250,250);
rj = zeros(250,250);
rk = zeros(100,100);
for i=1:10000
ri(i) = randi([-10000,10000],1,1);
end
tic;
inputMatrix(ri);
time(1) = toc;
for i=1:5000
rj(i) = randi([-10000,10000],1,1);
end
tic;
inputMatrix(rj);
time(2) = toc;
for i=1:1000
rk(i) = randi([-10000,10000],1,1);
end
tic;
inputMatrix(rj);
time(3) = toc;
Results:
time = 1.8009 0.5619 0.5545
no. non zero entires = 10 000, 5000, 1000
The results suggest there is a non linear relationship, and not order N
find gives you the indices of nonzero elements and sparse converts the matrix directly to a sparse matrix.

Vectorize octave/matlab codes

Following is the octave codes(part of kmeans)
centroidSum = zeros(K);
valueSum = zeros(K, n);
for i = 1 : m
for j = 1 : K
if(idx(i) == j)
centroidSum(j) = centroidSum(j) + 1;
valueSum(j, :) = valueSum(j, :) + X(i, :);
end
end
end
The codes work, is it possible to vectorize the codes?
It is easy to vectorize the codes without if statement,
but how could we vectorize the codes with if statement?
I assume the purpose of the code is to compute the centroids of subsets of a set of m data points in an n-dimensional space, where the points are stored in a matrix X (points x coordinates) and the vector idx specifies for each data point the subset (1 ... K) the point belongs to. Then a partial vectorization is:
centroid = zeros(K, n)
for j = 1 : K
centroid(j, :) = mean(X(idx == j, :));
end
The if is eliminated by indexing, in particular logical indexing: idx == j gives a boolean array which indicates which data points belong to subset j.
I think it might be possible to get rid of the second for-loop, too, but this would result in very convoluted, unintelligible code.
Brief introduction and solution code
This could be one fully vectorized approach based on -
accumarray: For accumulating summations as done for calulating valueSum. This also introduces a technique how one can use accumarray on a 2D matrix along a certain direction, which isn't possible in a straight-forward manner with it.
bsxfun: For calculating linear indices across all columns for matching row indices from idx.
Here's the implementation -
%// Store no. of columns in X for frequent usage later on
ncols = size(X,2);
%// Find indices in idx that are within [1:k] range, call them as labels
%// Also, find their locations in that range array, call those as pos
[pos,id] = ismember(idx,1:K);
labels = id(pos);
%// OR with bsxfun: [pos,labels] = find(bsxfun(#eq,idx(:),1:K));
%// Find all labels, i.e. across all columns of X
all_labels = bsxfun(#plus,labels(:),[0:ncols-1]*K);
%// Get truncated X corresponding to all indices matches across all columns
X_cut = X(pos,:);
%// Accumulate summations within each column based on the labels.
%// Note that accumarray doesn't accept matrices, so we were required
%// to create all_labels that had same labels within each column and
%// offsetted at constant intervals from consecutive columns
acc1 = accumarray(all_labels(:),X_cut(:));
%// Regularise accumulated array and reshape back to a 2D array version
acc1_reg2D = [acc1 ; zeros(K*ncols - numel(acc1),1)];
valueSum = reshape(acc1_reg2D,[],ncols);
centroidSum = histc(labels,1:K); %// Get labels counts as centroid sums
Benchmarking code
%// Datasize parameters
K = 5000;
n = 5000;
m = 5000;
idx = randi(9,1,m);
X = rand(m,n);
disp('----------------------------- With Original Approach')
tic
centroidSum1 = zeros(K,1);
valueSum1 = zeros(K, n);
for i = 1 : m
for j = 1 : K
if(idx(i) == j)
centroidSum1(j) = centroidSum1(j) + 1;
valueSum1(j, :) = valueSum1(j, :) + X(i, :);
end
end
end
toc, clear valueSum1 centroidSum1
disp('----------------------------- With Proposed Approach')
tic
%// ... Code from earlied mentioned section
toc
Runtime results
----------------------------- With Original Approach
Elapsed time is 1.235412 seconds.
----------------------------- With Proposed Approach
Elapsed time is 0.379133 seconds.
Not sure about its runtime performance but here's a non-convoluted vectorized implementation:
b = idx == 1:K;
centroids = (b' * X) ./ sum(b)';
Vectorizing the calculation makes a huge difference in performance. Benchmarking
The original code,
The partial vectorization from A. Donda and
The full vectorization from Tom,
gave me the following results:
Original Code: Elapsed time is 1.327877 seconds.
Partial Vectorization: Elapsed time is 0.630767 seconds.
Full Vectorization: Elapsed time is 0.021129 seconds.
Benchmarking code here:
%// Datasize parameters
K = 5000;
n = 5000;
m = 5000;
idx = randi(9,1,m);
X = rand(m,n);
fprintf('\nOriginal Code: ')
tic
centroidSum1 = zeros(K,1);
valueSum1 = zeros(K, n);
for i = 1 : m
for j = 1 : K
if(idx(i) == j)
centroidSum1(j) = centroidSum1(j) + 1;
valueSum1(j, :) = valueSum1(j, :) + X(i, :);
end
end
end
centroids = valueSum1 ./ centroidSum1;
toc, clear valueSum1 centroidSum1 centroids
fprintf('\nPartial Vectorization: ')
tic
centroids = zeros(K,n);
for k = 1:K
centroids(k,:) = mean( X(idx == k, :) );
end
toc, clear centroids
fprintf('\nFull Vectorization: ')
tic
centroids = zeros(K,n);
b = idx == 1:K;
centroids = (b * X) ./ sum(b)';
toc
Note, I added an extra line to the original code to element-wise divide valueSum1 by centroidSum1 to make the output of each type of code the same.
Finally, I know this isn't strictly an "answer", however I don't have enough reputation to add a comment, and I thought the benchmarking figures were useful to anyone who is learning MATLAB (like myself) and needs some extra motivation to master vectorization.

Recovering vector in MATLAB for loop

I am running a for loop in MATLAB. Each iteration produces a vector of length different than the vector created in the previous iteration. Is there any why to recover each individual vector? In the end I want to concatenate each of these vectors. My code is something like
for i=1:n
v = zeros(1,i)
end
so after i=n, v will be a one by n vector, but I also want to recover the vectors for any i. In my code, each vector, v, is not a zero row vector, but a vector of varying size. Thanks.
I'd already typed this when Rody's post (+1) came through so figured I might as well post it too. An alternate solution that is very slightly less efficient (I did some timed runs, the differences were marginal) than Rody's but avoids the complicated indexing is:
A = cell(1, n);
for i = 1:n
A{1, i} = zeros(1, i);
end
Soln = cat(2, A{:});
I store the varying length row vectors in a cell array through the loop then concatenate them in the final step.
The simplest way is like so:
w = [];
for i=1:n
v = zeros(1,i);
%# your stuff here
w = [w v];
end
Which produces the vector w, which is the concatenation of all generated vectors v.
Note however that this is slow, since w grows each iteration. A slightly more complicated but more efficient solution would be this:
w = zeros(1, sum(1:n) );
j = 1;
for i=1:n
v = zeros(1,i);
%# your stuff here
w(1, j:j+i-1) = v;
j = j+i;
end