Extract elements of matrix from a starting element and size - matlab

Sorry about the bad title, I'm struggling to word this question well. Basically what I want to do is extract elements from a 2d matrix, from row by row, taking out a number of elements (N) starting at a particular column (k). In for loops, this would look like.
A = magic(6);
k = [2,2,3,3,4,4]; % for example
N = 3;
for j = 1:length(A)
B(j,:) = A(j,k(j):k(j)+N-1);
end
I figure there must be a neater way to do it than that.

You could use bsxfun to create an array of indices to use. Then combine this with the row numbers and pass it to sub2ind.
inds = sub2ind(size(A), repmat(1:size(A, 1), 3, 1), bsxfun(#plus, k, (0:(N-1))')).';
B = A(inds);
Or alternately without sub2ind (but slightly more cryptic).
B = A(bsxfun(#plus, 1:size(A,1), ((bsxfun(#plus, k, (0:(N-1)).')-1) * size(A,1))).');

Here's one approach using bsxfun's masking capability and thus logical indexing -
C = (1:size(A,2))';
At = A.';
B = reshape(At(bsxfun(#ge,C,k) & bsxfun(#lt,C,k+N)),N,[]).';

Related

MATLAB quick find of a vector in matrix

I have a piece of code that works in the following way.
There is a matrix of size n x 2. Each element is an integer between 1 and some maximum, say m.
I want to search for rows in this matrix, that is, given [v1, v2], output the index of this.
Right now, I am using:
k = find(ismember(edges, [v1, v2], 'rows'));
However, this is the bottleneck in my code because this is in linear time.
I would like to implement some hashmap type structure for fast lookup. What would be an easy way to do this?
Since you know the number of columns how about this (assuming edges is the matrix to be searched):
idx = find(edges(:,1)==v1 & edges(:,2)==v2);
Note, that depending on how exactly you use the index you might be better off using the logical index that is created on the way:
idx = edges(:,1)==v1 & edges(:,2)==v2;
Hope this helps.
R2016b and beyond:
find(all(edges == [v1 v2], 2))
Prior:
find(all(bsxfun(#eq, edges, [v1 v2]), 2))
Try the following code:
M = [5 2; 10 1; 3 2; 4 4; 5 0]
N = [4 4]
ind=find(all(repmat(N,size(M,1),1)==M,2));
ind is the row where the matrix include the specific numbers in N.
Using accumarray can make an adjacency matrix to speed up your search:
A = accumarray(edges,1,[m m],#any,false)
and you can use indexing to search it
if(A(v1,v2))...
If m is very large you can create a sparse matrix:
A = accumarray(edges,1,[m m],#any,false,true)
Or if you need index of it the adjacency matrix can be cereated this way:
A = accumarray(edges,1:size(edgaes,1),[m m],#any,0,true);
so
index = A(v1,v2)
One option that gives me about a 30-40 times speedup over your code is doing the comparison for the entire first column, capturing a set of indices, then only checking the values of the second column at those indices:
ind = find(edges(:, 1) == v1);
k = ind(edges(ind, 2) == v2);
If you still need it done faster than that, you can use the containers.Map class to precompute a mapping of every possible [v1 v2] to the list of row indices where it occurs. One caveat is that the key type for the map can't be a vector of numbers, but since you are dealing with integers (ideally with m not being prohibitively large) you can convert [v1 v2] to a 2-character ASCII key. Here's how you can build the map:
mapObj = containers.Map('KeyType', 'char', 'ValueType', 'any');
[R, C] = meshgrid(1:m);
keys = [R(:) C(:)];
for keyIndex = 1:(m*m)
v = keys(keyIndex, :);
ind = find(edges(:, 1) == v(1));
mapObj(char(v)) = ind(edges(ind, 2) == v(2));
end
And you can access a value from the map very quickly like so:
k = mapObj(char([v1 v2]));

Logical index of structure with various dimensioned fields

Lets say I have a structure like this:
S.index = 1:10;
S.testMatrix = zeros(3,3,10);
for x = 1:10
S.testMatrix(:,:,x) = magic(3) + x;
end
S.other = reshape(0:39, 4, 10);
It contains a 1x10 vector, a 3x3x10 multi-paged array and a 4x10 matrix. Now say I want to select only the entries corresponding to the indices between 2 and 8. mask = S.index > 2 & S.index < 8;
I tried structfun(#(x) x(mask), S, 'UniformOutput', 0); first which correctly worked for only the vector, which makes perfect sense. So then I figured all I needed to do was expand my mask. So I did this.
test = structfun(#(x) x(repmat(mask, size(x, ndims(x) - 1), 1)), S, 'UniformOutput',0);
The expanded mask was correct for the matrix but not the multi-paged array. And the 2D matrix was flattened to a vector.
If I was going to index these elements individually I would do something like this:
S2.index = S.index(mask);
S2.other = S.other(:,mask);
S2.testMatrix = S.testMatrix(:,:,mask);
My use case is for hundreds of structures each with 20+ fields. How do I script the indexing? The exact problem occurs is limited to a structure with 1xN vectors, 3xN and 4xN matrices and 3x3xN arrays. The mask is constructed based on one of the vectors representing time. The field names are constant for each structure so I could brute force the thing and type in the commands and run it as a function, but I'm looking for an intelligent way to index it.
Update: Here is something that looks promising.
fn = fieldnames(S);
for x = 1:length(fn)
extraDim = repmat({':'}, 1, ndims(S.(fn{x})) - 1);
S2.(fn{x}) = S.(fn{x})(extraDim{:}, mask);
end
You can exploit the fact that the string ':' can be used as an index instead of :, and build a comma-separated list of that string repeated the appropriate number of times for each field:
s = {':',':'}; % auxilary cell array to generate the comma-separated list
S2 = structfun(#(f) f(s{1:ndims(f)-1}, mask), S, 'UniformOutput', false);

Matlab: reshape a vector by permuting?

I have the following vector u:
u=[a1,a2,a3,a4,b1,b2,b3,b4,c1,c2,c3,c4];
I want to permute the elements of of u to make the following vector, uNew:
uNew=[a1,b1,c1,a2,b2,c2,a3,b3,c3,a4,b4,c4];
I can think of no way of doing this other than with a for loop:
uNew=[];
for i=1:4
uNew=[uNew,u(i:4:end)];
end
But I'm hoping that a built-in function exits? Thanks!
Reshape it to a matrix which, read column by column, contains the order you want:
n=3 % number of categories (a,b,c)
u2=reshape(u,[],n).'
then convert it back to a vector:
u2=u2(:);
I'd use Daniel's approach. But just to provide an alternative:
m = 4; %// size of each initial "block"
[~, ind] = sort(mod(0:numel(u)-1,m)+1);
uNew = u(ind);
Note that this works because, as per sort's documentation,
The ordering of the elements in B (output) preserves the order of any equal elements in A (input)
Another approach:
N = 4;
uNew = u(mod(0:numel(u)-1, N) * N + floor((0:numel(u)-1)/N) + 1);

Treat each row of a matrix as a vector in a MATLAB function

Say I have a nxm matrix and want to treat each row as vectors in a function. So, if I have a function that adds vectors, finds the Cartesian product of vectors or for some reason takes the input of several vectors, I want that function to treat each row in a matrix as a vector.
This sounds like a very operation in Matlab. You can access the ith row of a matrix A using A(i, :). For example, to add rows i and j, you would do A(i, :) + A(j, :).
Given an nxm matrix A:
If you want to edit a single column/row you could use the following syntax: A(:, i) for the ith-column and A(i, :) for ith-row.
If you want to edit from a column/row i to a column/row j, you could use that syntax: A(:, i:j) or A(i:j, :)
If you want to edit (i.e.) from the penultimate column/row to the last one, you could you: A(:, end-1:end) or A(end-1:end, :)
EDIT:
I can't add a comment above because I don't have 50 points, but you should post the function setprod. I think you should be able to do what you want to do, by iterating the matrix you're passing as an argument, with a for-next statement.
I think you're going to have to loop:
Input
M = [1 2;
3 4;
5 6];
Step 1: Generate a list of all possible row pairs (row index numbers)
n = size(M,1);
row_ind = nchoosek(1:n,2)
Step 2: Loop through these indices and generate the product set:
S{n,n} = []; //% Preallocation of cell matrix
for pair = 1:size(row_ind,1)
p1 = row_ind(pair,1);
p2 = row_ind(pair,2);
S{p1,p2} = setprod(M(p1,:), M(p2,:))
end
Transform the matrix into a list of row vectors using these two steps:
Convert the matrix into a cell array of the matrix rows, using mat2cell.
Generate a comma-separated list from the cell array, using linear indexing of the cell contents.
Example: let
v1 = [1 2];
v2 = [10 20];
v3 = [11 12];
M = [v1; v2; v3];
and let fun be a function that accepts an arbitrary number of vectors as its input. Then
C = mat2cell(M, ones(1,size(M,1)));
result = fun(C{:});
is the same as result = fun(v1, v2, v3).

Selecting entries from a matrix without using a loop

I have two matrices A and B, both of which are Nx3 matrices.
I'm currently getting the maximum value and index for each row of matrix A using:
[maxA, idx] = max(A, [], 2)
idx(j) indicates which column contained the maximum for row j. Now I'd like to select those same positions from matrix B.
I've currently implemented this using a loop:
for j = 1:numel(idx)
maxB(j) = B(j, idx(j))
end
My current implementation is fast enough, although I prefer to avoid unneeded loops so is there a way to express this without a loop?
You can build a vector of linear indices (I expect B to be the same size as A):
vec_indices = sub2ind(size(A), 1:numel(idx), idx);
Then you can use that vector directly for lookup:
maxB = B(vec_indices)
You can construct the single dimension index into the matrix and get them that way. All multidimensional matrices in matlab can be addressed.
You can use
maxB = B(sub2ind([1:length(idx)]',idx(:)));
In one line:
maxB = B(A == max(A, [], 2) * ones(1, 3));
But this is not safe. It assumes unique values in every row of A.