Attempted to access index in vector - matlab

Here is part of a function that counts the Nyquist stability criterion. Function gives an error when vectors re or im do not have five elements:
Attempted to access im(5); index out of bounds because numel(im)=4.
Error in stability (line 27)
tran(w) = re(1) + re(2)*w.^1 + re(3)*w.^2 + re(4)*w.^3 +
re(5)w.^4 +1i(...
I want to assign 0 to the missing elements.
function answear=stability(re,im)
%% Function check stability of system
%re is real part of transmitation
%im is imagine part of transmitation
%% data
for n=1:length(re)
if(re(n) == [ ])
re(n) = 0;
end
end
for n=1:length(im)
if(im (n)== [ ])
im(n) = 0;
end
end
if( length(re) > length(im))
root = length(re);
else
root = length(im);
end
for w=1:root
tran(w) = re(1) + re(2)*w.^1 + re(3)*w.^2 + re(4)*w.^3 + re(5)*w.^4 +1i*(...
im(1) + im(2)*w.^1 + im(3)*w.^2 + im(4)*w.^3 +im(5)*w.^4);
end

Here are two ways to expand a vector to ensure it has at least 5 elements. Each working from a different thought but doing the same.
Most compact:
x = [1 2 3];
x(end+1:5) = 0;
Assigns zero to all elements behind the matrix till the fifth element.
However, if you already know the amount of elements, this is more compact:
x = [1 2 3];
if numel(x)<5
x(5) = 0;
end
Note that this will automatically expand with zeros untill it has 5 elements. The advantage of these methods it that it works, regardless of the orientation of your vector.

If you want to pad your vector with zeros to make certain it has at least 5 elements I suggest the following:
Make a vecotr of 5 zeros
Fill the first X elements of pad with your vector (lets call it A)
For examples with A begin less than 5 and A being more than 5 elements:
A= [1 2 3]
n=5
pad = zeros(1,n)
pad(1:length(A)) = A
clear
A = [5 6 7 8 9 4 3]
n=5
pad = zeros(1,n)
pad(1:length(A)) = A

Related

Simplify a Matlab code involving finding the position of maximum elements of array

I would like your help to make more efficient (maybe, by vectorising) the Matlab code below. The code below does essentially the following: take a row vector A; consider the maximum elements of such a row vector and let, for example, be i and j their positions; construct two columns vectors, the first with all zeros but a 1 positioned at i, the second with all zeros but a 1 positioned at j.
This is my attempt with loops, but it looks more complicated than needed.
clear
rng default
A=[3 2 3];
max_idx=ismember(A,max(A));
vertex=cell(size(A,2),1);
for j=1:size(max_idx,2)
if max_idx(j)>0
position=find(max_idx(j));
vertex_temp=zeros(size(A,2),1);
vertex_temp(position)=1;
vertex{j}=vertex_temp;
else
vertex{j}=[];
end
end
vertex=vertex(~cellfun('isempty',vertex));
Still using a for loop, but more readable:
A = [3 2 3];
% find max indices
max_idx = find(A == max(A));
vertex = cell(numel(max_idx),1);
for k = 1:numel(max_idx)
vertex{k} = zeros(size(A,2),1); % init zeros
vertex{k}(max_idx(k)) = 1; % set value in vector to 1
end
If you really wanted to avoid a for loop, you could probably also use something like this:
A=[3 2 3];
max_idx = find(A==max(A));
outMat = zeros(numel(A), numel(max_idx));
outMat((0:(numel(max_idx)-1)) * numel(A) + max_idx) = 1;
then optionally, if you want them in separate cells rather than columns of a matrix:
outCell = mat2cell(outMat, numel(A), ones(1,numel(max_idx)))';
However, I think this might be less simple and readable than the existing answers.
Is there a specific reason you want a cell array rather than a matrix?
If you can have it all in one vector:
A = [3 2 3]
B_rowvec = A == max(A)
B_colvec = B_rowvec'
If you need them separated into separate vectors:
A = [3 2 3]
Nmaxval = sum(A==max(A))
outmat = zeros(length(A),Nmaxval)
for i = 1:Nmaxval
outmat(find(A==max(A),i),i)=1;
end
outvec1 = outmat(:,1)
outvec2 = outmat(:,2)
Basically, the second input for find will specify which satisfactory instance of the first input you want.
so therefore
example = [ 1 2 3 1 2 3 1 2 3 ]
first = find(example == 1, 1) % returns 1
second = find(example == 1, 2) % returns 4
third = find(example == 1, 3) % returns 7

Shifting repeating rows to a new column in a matrix

I am working with a n x 1 matrix, A, that has repeating values inside it:
A = [0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4; 0;1;2;3;4]
which correspond to an n x 1 matrix of B values:
B = [2;4;6;8;10; 3;5;7;9;11; 4;6;8;10;12; 5;7;9;11;13]
I am attempting to produce a generalised code to place each repetition into a separate column and store it into Aa and Bb, e.g.:
Aa = [0 0 0 0 Bb = [2 3 4 5
1 1 1 1 4 5 6 7
2 2 2 2 6 7 8 9
3 3 3 3 8 9 10 11
4 4 4 4] 10 11 12 13]
Essentially, each repetition from A and B needs to be copied into the next column and then deleted from the first column
So far I have managed to identify how many repetitions there are and copy the entire column over to the next column and then the next for the amount of repetitions there are but my method doesn't shift the matrix rows to columns as such.
clc;clf;close all
A = [0;1;2;3;4;0;1;2;3;4;0;1;2;3;4;0;1;2;3;4];
B = [2;4;6;8;10;3;5;7;9;11;4;6;8;10;12;5;7;9;11;13];
desiredCol = 1; %next column to go to
destinationCol = 0; %column to start on
n = length(A);
for i = 2:1:n-1
if A == 0;
A = [ A(:, 1:destinationCol)...
A(:, desiredCol+1:destinationCol)...
A(:, desiredCol)...
A(:, destinationCol+1:end) ];
end
end
A = [...] retrieved from Move a set of N-rows to another column in MATLAB
Any hints would be much appreciated. If you need further explanation, let me know!
Thanks!
Given our discussion in the comments, all you need is to use reshape which converts a matrix of known dimensions into an output matrix with specified dimensions provided that the number of elements match. You wish to transform a vector which has a set amount of repeating patterns into a matrix where each column has one of these repeating instances. reshape creates a matrix in column-major order where values are sampled column-wise and the matrix is populated this way. This is perfect for your situation.
Assuming that you already know how many "repeats" you're expecting, we call this An, you simply need to reshape your vector so that it has T = n / An rows where n is the length of the vector. Something like this will work.
n = numel(A); T = n / An;
Aa = reshape(A, T, []);
Bb = reshape(B, T, []);
The third parameter has empty braces and this tells MATLAB to infer how many columns there will be given that there are T rows. Technically, this would simply be An columns but it's nice to show you how flexible MATLAB can be.
If you say you already know the repeated subvector, and the number of times it repeats then it is relatively straight forward:
First make your new A matrix with the repmat function.
Then remap your B vector to the same size as you new A matrix
% Given that you already have the repeated subvector Asub, and the number
% of times it repeats; An:
Asub = [0;1;2;3;4];
An = 4;
lengthAsub = length(Asub);
Anew = repmat(Asub, [1,An]);
% If you can assume that the number of elements in B is equal to the number
% of elements in A:
numberColumns = size(Anew, 2);
newB = zeros(size(Anew));
for i = 1:numberColumns
indexStart = (i-1) * lengthAsub + 1;
indexEnd = indexStart + An;
newB(:,i) = B(indexStart:indexEnd);
end
If you don't know what is in your original A vector, but you do know it is repetitive, if you assume that the pattern has no repeats you can use the find function to find when the first element is repeated:
lengthAsub = find(A(2:end) == A(1), 1);
Asub = A(1:lengthAsub);
An = length(A) / lengthAsub
Hopefully this fits in with your data: the only reason it would not is if your subvector within A is a pattern which does not have unique numbers, such as:
A = [0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0; 0;1;2;3;2;1;0;]
It is worth noting that from the above intuitively you would have lengthAsub = find(A(2:end) == A(1), 1) - 1;, But this is not necessary because you are already effectively taking the one off by only looking in the matrix A(2:end).

MATLAB separating array [duplicate]

I'm trying to elegantly split a vector. For example,
vec = [1 2 3 4 5 6 7 8 9 10]
According to another vector of 0's and 1's of the same length where the 1's indicate where the vector should be split - or rather cut:
cut = [0 0 0 1 0 0 0 0 1 0]
Giving us a cell output similar to the following:
[1 2 3] [5 6 7 8] [10]
Solution code
You can use cumsum & accumarray for an efficient solution -
%// Create ID/labels for use with accumarray later on
id = cumsum(cut)+1
%// Mask to get valid values from cut and vec corresponding to ones in cut
mask = cut==0
%// Finally get the output with accumarray using masked IDs and vec values
out = accumarray(id(mask).',vec(mask).',[],#(x) {x})
Benchmarking
Here are some performance numbers when using a large input on the three most popular approaches listed to solve this problem -
N = 100000; %// Input Datasize
vec = randi(100,1,N); %// Random inputs
cut = randi(2,1,N)-1;
disp('-------------------- With CUMSUM + ACCUMARRAY')
tic
id = cumsum(cut)+1;
mask = cut==0;
out = accumarray(id(mask).',vec(mask).',[],#(x) {x});
toc
disp('-------------------- With FIND + ARRAYFUN')
tic
N = numel(vec);
ind = find(cut);
ind_before = [ind-1 N]; ind_before(ind_before < 1) = 1;
ind_after = [1 ind+1]; ind_after(ind_after > N) = N;
out = arrayfun(#(x,y) vec(x:y), ind_after, ind_before, 'uni', 0);
toc
disp('-------------------- With CUMSUM + ARRAYFUN')
tic
cutsum = cumsum(cut);
cutsum(cut == 1) = NaN; %Don't include the cut indices themselves
sumvals = unique(cutsum); % Find the values to use in indexing vec for the output
sumvals(isnan(sumvals)) = []; %Remove NaN values from sumvals
output = arrayfun(#(val) vec(cutsum == val), sumvals, 'UniformOutput', 0);
toc
Runtimes
-------------------- With CUMSUM + ACCUMARRAY
Elapsed time is 0.068102 seconds.
-------------------- With FIND + ARRAYFUN
Elapsed time is 0.117953 seconds.
-------------------- With CUMSUM + ARRAYFUN
Elapsed time is 12.560973 seconds.
Special case scenario: In cases where you might have runs of 1's, you need to modify few things as listed next -
%// Mask to get valid values from cut and vec corresponding to ones in cut
mask = cut==0
%// Setup IDs differently this time. The idea is to have successive IDs.
id = cumsum(cut)+1
[~,~,id] = unique(id(mask))
%// Finally get the output with accumarray using masked IDs and vec values
out = accumarray(id(:),vec(mask).',[],#(x) {x})
Sample run with such a case -
>> vec
vec =
1 2 3 4 5 6 7 8 9 10
>> cut
cut =
1 0 0 1 1 0 0 0 1 0
>> celldisp(out)
out{1} =
2
3
out{2} =
6
7
8
out{3} =
10
For this problem, a handy function is cumsum, which can create a cumulative sum of the cut array. The code that produces an output cell array is as follows:
vec = [1 2 3 4 5 6 7 8 9 10];
cut = [0 0 0 1 0 0 0 0 1 0];
cutsum = cumsum(cut);
cutsum(cut == 1) = NaN; %Don't include the cut indices themselves
sumvals = unique(cutsum); % Find the values to use in indexing vec for the output
sumvals(isnan(sumvals)) = []; %Remove NaN values from sumvals
output = {};
for i=1:numel(sumvals)
output{i} = vec(cutsum == sumvals(i)); %#ok<SAGROW>
end
As another answer shows, you can use arrayfun to create a cell array with the results. To apply that here, you'd replace the for loop (and the initialization of output) with the following line:
output = arrayfun(#(val) vec(cutsum == val), sumvals, 'UniformOutput', 0);
That's nice because it doesn't end up growing the output cell array.
The key feature of this routine is the variable cutsum, which ends up looking like this:
cutsum =
0 0 0 NaN 1 1 1 1 NaN 2
Then all we need to do is use it to create indices to pull the data out of the original vec array. We loop from zero to max and pull matching values. Notice that this routine handles some situations that may arise. For instance, it handles 1 values at the very beginning and very end of the cut array, and it gracefully handles repeated ones in the cut array without creating empty arrays in the output. This is because of the use of unique to create the set of values to search for in cutsum, and the fact that we throw out the NaN values in the sumvals array.
You could use -1 instead of NaN as the signal flag for the cut locations to not use, but I like NaN for readability. The -1 value would probably be more efficient, as all you'd have to do is truncate the first element from the sumvals array. It's just my preference to use NaN as a signal flag.
The output of this is a cell array with the results:
output{1} =
1 2 3
output{2} =
5 6 7 8
output{3} =
10
There are some odd conditions we need to handle. Consider the situation:
vec = [1 2 3 4 5 6 7 8 9 10 11 12 13 14];
cut = [1 0 0 1 1 0 0 0 0 1 0 0 0 1];
There are repeated 1's in there, as well as a 1 at the beginning and end. This routine properly handles all this without any empty sets:
output{1} =
2 3
output{2} =
6 7 8 9
output{3} =
11 12 13
You can do this with a combination of find and arrayfun:
vec = [1 2 3 4 5 6 7 8 9 10];
N = numel(vec);
cut = [0 0 0 1 0 0 0 0 1 0];
ind = find(cut);
ind_before = [ind-1 N]; ind_before(ind_before < 1) = 1;
ind_after = [1 ind+1]; ind_after(ind_after > N) = N;
out = arrayfun(#(x,y) vec(x:y), ind_after, ind_before, 'uni', 0);
We thus get:
>> celldisp(out)
out{1} =
1 2 3
out{2} =
5 6 7 8
out{3} =
10
So how does this work? Well, the first line defines your input vector, the second line finds how many elements are in this vector and the third line denotes your cut vector which defines where we need to cut in our vector. Next, we use find to determine the locations that are non-zero in cut which correspond to the split points in the vector. If you notice, the split points determine where we need to stop collecting elements and begin collecting elements.
However, we need to account for the beginning of the vector as well as the end. ind_after tells us the locations of where we need to start collecting values and ind_before tells us the locations of where we need to stop collecting values. To calculate these starting and ending positions, you simply take the result of find and add and subtract 1 respectively.
Each corresponding position in ind_after and ind_before tell us where we need to start and stop collecting values together. In order to accommodate for the beginning of the vector, ind_after needs to have the index of 1 inserted at the beginning because index 1 is where we should start collecting values at the beginning. Similarly, N needs to be inserted at the end of ind_before because this is where we need to stop collecting values at the end of the array.
Now for ind_after and ind_before, there is a degenerate case where the cut point may be at the end or beginning of the vector. If this is the case, then subtracting or adding by 1 will generate a start and stopping position that's out of bounds. We check for this in the 4th and 5th line of code and simply set these to 1 or N depending on whether we're at the beginning or end of the array.
The last line of code uses arrayfun and iterates through each pair of ind_after and ind_before to slice into our vector. Each result is placed into a cell array, and our output follows.
We can check for the degenerate case by placing a 1 at the beginning and end of cut and some values in between:
vec = [1 2 3 4 5 6 7 8 9 10];
cut = [1 0 0 1 0 0 0 1 0 1];
Using this example and the above code, we get:
>> celldisp(out)
out{1} =
1
out{2} =
2 3
out{3} =
5 6 7
out{4} =
9
out{5} =
10
Yet another way, but this time without any loops or accumulating at all...
lengths = diff(find([1 cut 1])) - 1; % assuming a row vector
lengths = lengths(lengths > 0);
data = vec(~cut);
result = mat2cell(data, 1, lengths); % also assuming a row vector
The diff(find(...)) construct gives us the distance from each marker to the next - we append boundary markers with [1 cut 1] to catch any runs of zeros which touch the ends. Each length is inclusive of its marker, though, so we subtract 1 to account for that, and remove any which just cover consecutive markers, so that we won't get any undesired empty cells in the output.
For the data, we mask out any elements corresponding to markers, so we just have the valid parts we want to partition up. Finally, with the data ready to split and the lengths into which to split it, that's precisely what mat2cell is for.
Also, using #Divakar's benchmark code;
-------------------- With CUMSUM + ACCUMARRAY
Elapsed time is 0.272810 seconds.
-------------------- With FIND + ARRAYFUN
Elapsed time is 0.436276 seconds.
-------------------- With CUMSUM + ARRAYFUN
Elapsed time is 17.112259 seconds.
-------------------- With mat2cell
Elapsed time is 0.084207 seconds.
...just sayin' ;)
Here's what you need:
function spl = Splitting(vec,cut)
n=1;
j=1;
for i=1:1:length(b)
if cut(i)==0
spl{n}(j)=vec(i);
j=j+1;
else
n=n+1;
j=1;
end
end
end
Despite how simple my method is, it's in 2nd place for performance:
-------------------- With CUMSUM + ACCUMARRAY
Elapsed time is 0.264428 seconds.
-------------------- With FIND + ARRAYFUN
Elapsed time is 0.407963 seconds.
-------------------- With CUMSUM + ARRAYFUN
Elapsed time is 18.337940 seconds.
-------------------- SIMPLE
Elapsed time is 0.271942 seconds.
Unfortunately there is no 'inverse concatenate' in MATLAB. If you wish to solve a question like this you can try the below code. It will give you what you looking for in the case where you have two split point to produce three vectors at the end. If you want more splits you will need to modify the code after the loop.
The results are in n vector form. To make them into cells, use num2cell on the results.
pos_of_one = 0;
% The loop finds the split points and puts their positions into a vector.
for kk = 1 : length(cut)
if cut(1,kk) == 1
pos_of_one = pos_of_one + 1;
A(1,one_pos) = kk;
end
end
F = vec(1 : A(1,1) - 1);
G = vec(A(1,1) + 1 : A(1,2) - 1);
H = vec(A(1,2) + 1 : end);

Extract every element except every n-th element of vector

Given a vector
A = [1,2,3,...,100]
I want to extract all elements, except every n-th. So, for n=5, my output should be
B = [1,2,3,4,6,7,8,9,11,...]
I know that you can access every n-th element by
A(5:5:end)
but I need something like the inverse command.
If this doesn't exist I would iterate over the elements and skip every n-th entry, but that would be the dirty way.
You can eliminate elements like this:
A = 1:100;
removalList = 1:5:100;
A(removalList) = [];
Use a mask. Let's say you have
A = 1 : 100;
Then
m = mod(0 : length(A) - 1, 5);
will be a vector of the same length as A containing the repeated sequence 0 1 2 3 4.
You want everything from A except the elements where m == 4, i.e.
B = A(m ~= 4);
will result in
B == [1 2 3 4 6 7 8 9 11 12 13 14 16 ...]
Or you can use logical indexing:
n = 5; % remove the fifth
idx = logical(zeroes(size(A))); % creates a blank mask
idx(n) = 1; % makes the nth element 1
A(idx) = []; % ta-da!
About the "inversion" command you cited, it is possible to achieve that behavior using logical indexing. You can negate the vector to transform every 1 in 0, and vice-versa.
So, this code will remove any BUT the fifth element:
negatedIdx = ~idx;
A(negatedIdx) = [];
why not use it like this?
say A is your vector
A = 1:100
n = 5
B = A([1:n-1,n+1:end])
then
B=[1 2 3 4 6 7 8 9 10 ...]
One possible solution for your problem is the function setdiff().
In your specific case, the solution would be:
lenA = length(A);
index = setdiff(1:lenA,n:n:lenA);
B = A(index)
If you do it all at once, you can avoid both extra variables:
B = A( setdiff(1:end,n:n:end) )
However, Logical Indexing is a faster option, as tested:
lenA = length(A);
index = true(1, lenA);
index(n:n:lenA) = false;
B = A(index)
All these codes assume that you have specified the variable n, and can adapt to a different value.
For the shortest amount of code, you were nearly there all ready. If you want to adjust your existing array use:
A(n:n:end)=[];
Or if you want a new array called B:
B=A;
B(n:n:end)=[];

How can I get counterdiagonals of a matrix and concatenate them?

Short Version
How can I do concatMap in MATLAB? I'm trying to build a single vector from a series of smaller, differently sized vectors. I know I can do:
result = [];
for i=1:N
result = [result nextPart(i)];
end
but that has a serious speed impact and there must be a smarter way to do concatMap.
Long Version
I'm trying to write a MATLAB function that returns the counterdiagonals of a block. For example, if you have the block:
1 2 4
3 5 7
6 8 9
then counterDiagonals(block) should return [1 2 3 4 5 6 7 8 9].
I have a function that will find a single counter diagonal of a block. i.e. counterDiagonal(x, 3) will return [4 5 6].
Therefore, counterDiagonals should be as simple as concatMap counterDiagonal(x, i) (1:N) where N is (2*length(block)-1). How can I do this in MATLAB in an efficient way?
One problem with the accepted answer: if the matrix A had zeros, they will be incorrectly removed from the result.. Instead you should work on the indices of the elements:
A = [0 2 4; 3 5 7; 6 8 9]; %# Sample matrix (contains zeros)
ind = reshape(1:numel(A), size(A)); %# indices of elements
ind = fliplr( spdiags( fliplr(ind) ) ); %# get the anti-diagonals (or use ROT90)
ind(ind==0) = []; %# keep non-zero indices
result = A(ind); %# get elements in desired order
This is very similar to this answer I gave in a previous question (the difference was that the anti-digaonals were in reverse order).
I believe what you want to do can be accomplished using the functions ROT90 and SPDIAGS:
A = [1 2 4; 3 5 7; 6 8 9]; %# Sample matrix
result = rot90(A); %# Rotate the matrix counter-clockwise
result = spdiags(result); %# Find all the diagonals
result = result(result ~= 0).'; %'# Remove zero padding and format the results
%# into a row vector
And you should end up with result = [1 2 3 4 5 6 7 8 9].
EDIT: As Amro mentions in a comment, the above code assumes that there are no zeroes in the original matrix A. If there are zeroes in the original matrix, one solution is to replace them with a non-zero flag value that you know doesn't appear in the original matrix (like, for example, NaN), run the above code, then replace the flag values in the result:
A = [0 2 4; 3 0 7; 6 8 0]; %# Sample matrix
result = rot90(A); %# Rotate the matrix counter-clockwise
result(result == 0) = nan; %# Replace zeroes with NaN
result = spdiags(result); %# Find all the diagonals
result = result(result ~= 0).'; %'# Remove zero padding and format the results
%# into a row vector
result(isnan(result)) = 0; %# Put the original zeroes back
Short version:
If you preassign your result array, everything will be a lot faster.
result = zeros(1,knownLengthOfResultsArray); %# such as "numel(block)"
ct = 1;
for i=1:N
tmp = nextPart(i);
nTmp = length(tmp);
result(ct:ct+nTmp-1) = tmp;
ct = ct + nTmp;
end
Long version:
However, it may be even more efficient to rewrite your algorithm. See e.g. the answers to this question (use fliplr on your array first), or #gnovice's answer.