Matrix power help/Matlab - matlab

I want to raise a matrix to a next matrix and subtrat one before taking the product.
e.g.
A = [2 3 5
2 3 0]
B = [2 2 1
1 2 0]
so prod(A.^B-1) would be:
first row (2^2-1)*(3^2-1)*(5^1-1)=96
second row (2^1-1)*(3^2-1)=8
and we would have prod(A.^B-1) = 96, 81. the trick also to skip past the zero, i keep getting zero or NaN, i think the zero is being calculated as well.
Is there a way to code this,
this is the code I have in mind
if A~=0 && B~=0
prod(A.^B-1)
end

You could do it like this using logical indexing to replace instances where A.^B-1 is 0:
A = [2 3 5;2 3 0];
B = [2 2 1;1 2 0];
C = A.^B-1;
C(C==0) = 1; % Replace zeros with ones
D = prod(C,2) % Product across the columns
which returns
D =
96
8
provided that you remove the zeros, I don't think that you should get NaN unless your original matrices contain it. However, You can replace it in the same manner as well (C(isnan(C)) = 1;).

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

MATLAB: Creating a matrix with all possible group combinations

I'm running an experiment with lots of conditions, and particular numbers of groups in each condition.
A. 3 groups
B. 3 groups
C. 2 groups
D. 3 groups
E. 3 groups
I've worked out that there are 3×3×2×3×3 = 162 possible combinations of groups.
I want to create a MATLAB matrix with 162 rows and 5 columns. That is, one row for each combination and one column to indicate the value for each group.
So, for instance, the first row would be [1 1 1 1 1], indicating that this combination is group 1 for all conditions. The second row would be [1 1 1 1 2], indicating that it's group 1 for all conditions except for the last which is group 2. The 162nd and final row would be [3 3 2 3 3].
M = 1 1 1 1 1
1 1 1 1 2
.........
3 3 2 3 3
What's the most efficient way to achieve this? I realise I could use a loop, but feel sure there's a better way. I thought maybe the perms function would work but I can't see how.
You can use combvec (see last line, the rest is only generating test data):
% A. 3 groups
% B. 3 groups
% C. 2 groups
% D. 3 groups
% E. 3 groups
ngroups = zeros(5, 1);
ngroups(1) = 3;
ngroups(2) = 3;
ngroups(3) = 2;
ngroups(4) = 3;
ngroups(5) = 3;
v = {};
for i = 1:length(ngroups)
v{i} = 1:ngroups(i) % generate a vector of valid group indices
end
% get all possible combinations
x = combvec( v{:} )
As this will return a 5 x 162 double you need to transpose the resulting matrix x:
x.'

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).

Eliminating zeros in a matrix - Matlab

Hi I have the following matrix:
A= 1 2 3;
0 4 0;
1 0 9
I want matrix A to be:
A= 1 2 3;
1 4 9
PS - semicolon represents the end of each column and new column starts.
How can I do that in Matlab 2014a? Any help?
Thanks
The problem you run into with your problem statement is the fact that you don't know the shape of the "squeezed" matrix ahead of time - and in particular, you cannot know whether the number of nonzero elements is a multiple of either the rows or columns of the original matrix.
As was pointed out, there is a simple function, nonzeros, that returns the nonzero elements of the input, ordered by columns. In your case,
A = [1 2 3;
0 4 0;
1 0 9];
B = nonzeros(A)
produces
1
1
2
4
3
9
What you wanted was
1 2 3
1 4 9
which happens to be what you get when you "squeeze out" the zeros by column. This would be obtained (when the number of zeros in each column is the same) with
reshape(B, 2, 3);
I think it would be better to assume that the number of elements may not be the same in each column - then you need to create a sparse array. That is actually very easy:
S = sparse(A);
The resulting object S is a sparse array - that is, it contains only the non-zero elements. It is very efficient (both for storage and computation) when lots of elements are zero: once more than 1/3 of the elements are nonzero it quickly becomes slower / bigger. But it has the advantage of maintaining the shape of your matrix regardless of the distribution of zeros.
A more robust solution would have to check the number of nonzero elements in each column and decide what the shape of the final matrix will be:
cc = sum(A~=0);
will count the number of nonzero elements in each column of the matrix.
nmin = min(cc);
nmax = max(cc);
finds the smallest and largest number of nonzero elements in any column
[i j s] = find(A); % the i, j coordinates and value of nonzero elements of A
nc = size(A, 2); % number of columns
B = zeros(nmax, nc);
for k = 1:nc
B(1:cc(k), k) = s(j == k);
end
Now B has all the nonzero elements: for columns with fewer nonzero elements, there will be zero padding at the end. Finally you can decide if / how much you want to trim your matrix B - if you want to have no zeros at all, you will need to trim some values from the longer columns. For example:
B = B(1:nmin, :);
Simple solution:
A = [1 2 3;0 4 0;1 0 9]
A =
1 2 3
0 4 0
1 0 9
A(A==0) = [];
A =
1 1 2 4 3 9
reshape(A,2,3)
ans =
1 2 3
1 4 9
It's very simple though and might be slow. Do you need to perform this operation on very large/many matrices?
From your question it's not clear what you want (how to arrange the non-zero values, specially if the number of zeros in each column is not the same). Maybe this:
A = reshape(nonzeros(A),[],size(A,2));
Matlab's logical indexing is extremely powerful. The best way to do this is create a logical array:
>> lZeros = A==0
then use this logical array to index into A and delete these zeros
>> A(lZeros) = []
Finally, reshape the array to your desired size using the built in reshape command
>> A = reshape(A, 2, 3)

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.