How to Put Matrix in a Look and store values? - matlab

I want to put one matrix in a look and want to get values of that matrix after that loop and want to store it. Example:
N =10;
C=eye(N);
P=[.1 .2 .3];
for k=1:3
Rp=C;
for i=1:N
if(rand < P(1,k))
Rp(i,:) = 0;
end
end
end
From the above function it is clear that i will get 3 Rp matrix as i have 3 values of P. How to store the values of all these 3 Rp? Any suggestions?

I think this is what you are looking for, just simply store the results at the end of the main loop into a cell array.
N=10;
C=eye(N);
p=[.1 .2 .3];
RpMats = cell(1,numel(p));
for k=1:numel(p)
Rp=C;
for i=1:N
if(rand < p(1,k))
Rp(i,:) = 0;
end
end
RpMats{k} = Rp;
end
RpMats is a cell array where index 1 corresponds with the probability at index 1.

Related

Looping through to find max value without using max()

I'm trying to iterate in MATLAB (not allowed to use in built functions) to find the maximum value of each row in a certain matrix. I've been able to find the max value of the whole matrix but am unsure about isolating the row and finding the max value (once again without using max()).
My loop currently looks like this:
for i = 1:size(A, 1)
for j = 1:size(A, 2)
if A(i, j) > matrix_max
matrix_max = A(i, j);
row = i;
column = j;
end
end
end
You need a vector of results, not a single value. Note you could initialise this to zero. Don't initialise to zero unless you know you only have positive values. Instead, initialise to -inf using -inf*ones(...), as all values are greater than negative infinity. Or (see the bottom code block) initialise to the first column of A.
% Set up results vector, same number of rows as A, start at negative infinity
rows_max = -inf*ones(size(A,1),1);
% Set up similar to track column number. No need to track row number as doing each row!
col_nums = zeros(size(A,1),1);
% Loop through. i and j = sqrt(-1) by default in MATLAB, use ii and jj instead
for ii = 1:size(A,1)
for jj = 1:size(A,2)
if A(ii,jj) > rows_max(ii)
rows_max(ii) = A(ii,jj);
col_nums(ii) = jj;
end
end
end
Note that if vectorisation doesn't violate your "no built-ins" rule (it should be fine, it's making the most of the MATLAB language), then you can remove the outer (row) loop
rows_max = -inf*ones(size(A,1),1);
col_nums = zeros(size(A,1),1);
for jj = 1:size(A,2)
% Get rows where current column is larger than current max stored in row_max
idx = A(:,jj) > rows_max;
% Store new max values
rows_max(idx) = A(idx,jj);
% Store new column indices
col_nums(idx) = jj;
end
Even better, you can cut your loop short by 1, and initialise to the first column of A.
rows_max = A(:,1); % Set current max to the first column
col_nums = ones(size(A,1),1); % ditto
% Loop from 2nd column now that we've already used the first column
for jj = 2:size(A,2)
idx = A(:,jj) > rows_max;
rows_max(idx) = A(idx,jj);
col_nums(idx) = jj;
end
You can modified it likes the following to get each max for each row:
% initialize
matrix_max = zeros(size(A,1),1);
columns = zeros(size(A,1),1);
% find max
for i = 1:size(A, 1)
matrix_max(i) = A(i,1);
columns(i) = 1;
for j = 2:size(A, 2)
if A(i, j) > matrix_max(i)
matrix_max(i) = A(i, j);
columns(i) = j;
end
end
end

Swapping rows in a row echelon

I'm trying to make a program that computes, given any matrix A, its echelon form. Here is my code:
function A = myrref(A)
[m,n]=size(A);
for j=1:min(m,n)
A(j,:) = A(j,:)/A(j,j);
for i = j+1:m
A(i,:)= A(i,:)- A(j,:)*A(i,j);
if A(i,i) == 0
row1=A(i,:);
A(i,:)=A(i+1,:);
A(i+1,:)=row1;
end
end
end
It seems to work almost fine, but I still have a problem when swapping rows. For instance, when trying to get echelon form of matrix A=[1 1 1; 2 2 1; 1 2 2], I obtain [1 1 1; 0.5 1 1; 0 0 -1] which is not what I want. Do I need to add another loop that takes care of the 0.5 in the second row first column?
Firstly, it is simplier to use while loop for j because j is not necessarily growing on each iteration. The leading coefficient is not necessarily located on the main diagonal; when all the elements below the leading 0 are zeros, the leading coefficient position shifts to the right.
Secondly, the leading coefficient should be checked before A(j,:)/A(j,j) (to prevent division by 0)
Thirdly, the temporary is not needed to swap the rows as A([i j],:)= A([j i],:)
swaps the ith and jth rows of A.
Here is my version of myrref:
function A = myrref(A)
[m,n]=size(A);
j= 1; % the row index of the leading coefficient position
k= 1; % the column index of the leading coefficient position
while j<m && k<=n
if A(j,k)==0 % we need to change the row order
zeroindex= find(A(j+1:end,k)~=0); % find nonzero elements below A(j,k)
if isempty(zeroindex)
k= k+1; % there is no such elements; shift to the right
else
% swap the rows
A([j zeroindex(1)+j],:)= A([zeroindex(1)+j j],:);
end
else
A(j,:) = A(j,:)/A(j,k);
for i= j+1:m
A(i,:)= A(i,:)- A(j,:)*A(i,k);
end
j= j+1; k= k+1;
end
end
Just as #percusse said you need to finish the loop also your pivot should only go to m-1
Edit: Added an initial pivot based on #AVK's comment
function A = myrref(A)
[m,n]=size(A);
for i = 1:m-1
if A(i,i) == 0
row1=A(i,:);
A(i,:)=A(i+1,:);
A(i+1,:)=row1;
end
end
for j=1:min(m,n)
A(j,:) = A(j,:)/A(j,j);
for i = j+1:m
A(i,:)= A(i,:)- A(j,:)*A(i,j);
end
for i = j+1:m-1
if A(i,i) == 0
row1=A(i,:);
A(i,:)=A(i+1,:);
A(i+1,:)=row1;
end
end
end

MATLAB replacing some elements from a vector

If i have a vector, lets say L=[10;10;10;11;11;13;13] which is associated to another vector X=[1;6;65;34;21;73;14] and I want to create a third vector, Z, with almost all the elements in X, but just replacing a 0 in X when the element (i,j) from L changes. Lets say that the result that I want should look like this Z=[1;6;65;0;21;0;14]
Any ideas how to solve this?
I would be really thankful :)
That's easy:
X = [1;6;65;34;21;73;14];
L = [10;10;10;11;11;13;13];
Z = X;
ind = [false; diff(L)~=0]; %// logical index of values to be set to 0
Z(ind) = 0;
This works by computing a logical index ind = [false; diff(L)~=0] of the elements where a change has ocurred. The initial false is needed because the first element doesn't have a previous one to compare with. The logical index is used to select which values of Z should be set to 0.
This should work
Z = zeros(length(L))
for i = 2:length(L)
if(L(i-1) == L(i)
Z(i) = X(i);
else
Z(i) = 0;
end
end

Calculating overlap in Mx2 and Nx2 matrices

I have two matrices A and B, both contain a list of event start and stop times:
A(i,1) = onset time of event i
A(i,2) = offset time of event i
B(j,1) = onset of event j
...
My goal is to get two lists of indecies aIdx and bIdx such that A(aIdx,:) and B(bIdx,:) contain the sets of events that are overlapping.
I've been scratching my head all day trying to figure this one out. Is there a quick, easy, matlaby way to do this?
I can do it using for loops but this seems kind of hacky for matlab:
aIdx = [];
bIdx = []
for i=1:size(A,1)
for j=i:size(B,1)
if overlap(A(i,:), B(j,:)) % overlap is defined elsewhere
aIdx(end+1) = i;
bIdx(end+1) = j;
end
end
end
Here's a zero loop solution:
overlap = #(x, y)y(:, 1) < x(:, 2) & y(:, 2) > x(:, 1)
[tmp1, tmp2] = meshgrid(1:size(A, 1), 1:size(B, 1));
M = reshape(overlap(A(tmp1, :), B(tmp2, :)), size(B, 1), [])';
[aIdx, bIdx] = find(M);
You can do it with one loop:
aIdx = false(size(A,1),1);
bIdx = false(size(B,1),1);
for k = 1:size(B,1)
ai = ( A(:,1) >= B(k,1) & A(:,1) <= B(k,2) ) | ...
( A(:,2) >= B(k,1) & A(:,2) <= B(k,2) );
if any(ai), bIdx(k) = true; end
aIdx = aIdx | ai;
end
There is a way to create a vectorized algorithm. (I wrote a similar function before, but cannot find it right now.) A simply workflow is to (1) combine both matrices, (2) create an index to indicate source of each event, (3) create a matrix indicating start and stop positions, (4) vectorized and sort, (5) find overlaps with diff, cumsum, or combination.
overlap_matrix = zeros(size(A,1),size(B,1))
for jj = 1:size(B,1)
overlap_matrix(:,jj) = (A(:,1) <= B(jj,1)).*(B(jj,1) <= A(:,2));
end
[r,c] = find(overlap_matrix)
% Now A(r(i),:) overlaps with B(c(i),:)
% Modify the above conditional if you want to also check
% whether events in A start in-between the events in B
% as I am only checking the first half of the conditional
% for simplicity.
Completely vectorized code without repmat or reshape (hopefully faster too). I have assumed that the function "overlap" can give a vector of 1's and 0's if complete pairs of A(req_indices,:) and B(req_indices,:) are fed to it. If overlap can return a vector output, then the vectorization can be performed as given below.
Let rows in A matrix be Ra and Rows in B matrix be Rb,
AA=1:Ra;
AAA=AA(ones(Rb,1),:);
AAAA=AAA(:); % all indices of A arranged in desired format, i.e. [11...1,22..2,33...3, ...., RaRa...Ra]'
BB=(1:Rb)';
BBB=BB(:,ones(Ra,1));
BBBB=BBB(:);% all indices of B arranged in desired format, i.e. [123...Rb, 123...Rb,....,123...Rb]'
% Use overlap function
Result_vector = overlap(A(AAAA,:), B(BBBB,:));
Result_vector_without_zeros = find(Result_vector);
aIdx = AAAA(Results_vector_without_zeros);
bIdx = BBBB(Results_vector_without_zeros);
DISADVANTAGE : TOO MUCH RAM CONSUMPTION FOR LARGER MATRICES

Vectorizing sums of different diagonals in a matrix

I want to vectorize the following MATLAB code. I think it must be simple but I'm finding it confusing nevertheless.
r = some constant less than m or n
[m,n] = size(C);
S = zeros(m-r,n-r);
for i=1:m-r+1
for j=1:n-r+1
S(i,j) = sum(diag(C(i:i+r-1,j:j+r-1)));
end
end
The code calculates a table of scores, S, for a dynamic programming algorithm, from another score table, C.
The diagonal summing is to generate scores for individual pieces of the data used to generate C, for all possible pieces (of size r).
Thanks in advance for any answers! Sorry if this one should be obvious...
Note
The built-in conv2 turned out to be faster than convnfft, because my eye(r) is quite small ( 5 <= r <= 20 ). convnfft.m states that r should be > 20 for any benefit to manifest.
If I understand correctly, you're trying to calculate the diagonal sum of every subarray of C, where you have removed the last row and column of C (if you should not remove the row/col, you need to loop to m-r+1, and you need to pass the entire array C to the function in my solution below).
You can do this operation via a convolution, like so:
S = conv2(C(1:end-1,1:end-1),eye(r),'valid');
If C and r are large, you may want to have a look at CONVNFFT from the Matlab File Exchange to speed up calculations.
Based on the idea of JS, and as Jonas pointed out in the comments, this can be done in two lines using IM2COL with some array manipulation:
B = im2col(C, [r r], 'sliding');
S = reshape( sum(B(1:r+1:end,:)), size(C)-r+1 );
Basically B contains the elements of all sliding blocks of size r-by-r over the matrix C. Then we take the elements on the diagonal of each of these blocks B(1:r+1:end,:), compute their sum, and reshape the result to the expected size.
Comparing this to the convolution-based solution by Jonas, this does not perform any matrix multiplication, only indexing...
I would think you might need to rearrange C into a 3D matrix before summing it along one of the dimensions. I'll post with an answer shortly.
EDIT
I didn't manage to find a way to vectorise it cleanly, but I did find the function accumarray, which might be of some help. I'll look at it in more detail when I am home.
EDIT#2
Found a simpler solution by using linear indexing, but this could be memory-intensive.
At C(1,1), the indexes we want to sum are 1+[0, m+1, 2*m+2, 3*m+3, 4*m+4, ... ], or (0:r-1)+(0:m:(r-1)*m)
sum_ind = (0:r-1)+(0:m:(r-1)*m);
create S_offset, an (m-r) by (n-r) by r matrix, such that S_offset(:,:,1) = 0, S_offset(:,:,2) = m+1, S_offset(:,:,3) = 2*m+2, and so on.
S_offset = permute(repmat( sum_ind, [m-r, 1, n-r] ), [1, 3, 2]);
create S_base, a matrix of base array addresses from which the offset will be calculated.
S_base = reshape(1:m*n,[m n]);
S_base = repmat(S_base(1:m-r,1:n-r), [1, 1, r]);
Finally, use S_base+S_offset to address the values of C.
S = sum(C(S_base+S_offset), 3);
You can, of course, use bsxfun and other methods to make it more efficient; here I chose to lay it out for clarity. I have yet to benchmark this to see how it compares with the double-loop method though; I need to head home for dinner first!
Is this what you're looking for? This function adds the diagonals and puts them into a vector similar to how the function 'sum' adds up all of the columns in a matrix and puts them into a vector.
function [diagSum] = diagSumCalc(squareMatrix, LLUR0_ULLR1)
%
% Input: squareMatrix: A square matrix.
% LLUR0_ULLR1: LowerLeft to UpperRight addition = 0
% UpperLeft to LowerRight addition = 1
%
% Output: diagSum: A vector of the sum of the diagnols of the matrix.
%
% Example:
%
% >> squareMatrix = [1 2 3;
% 4 5 6;
% 7 8 9];
%
% >> diagSum = diagSumCalc(squareMatrix, 0);
%
% diagSum =
%
% 1 6 15 14 9
%
% >> diagSum = diagSumCalc(squareMatrix, 1);
%
% diagSum =
%
% 7 12 15 8 3
%
% Written by M. Phillips
% Oct. 16th, 2013
% MIT Open Source Copywrite
% Contact mphillips#hmc.edu fmi.
%
if (nargin < 2)
disp('Error on input. Needs two inputs.');
return;
end
if (LLUR0_ULLR1 ~= 0 && LLUR0_ULLR1~= 1)
disp('Error on input. Only accepts 0 or 1 as input for second condition.');
return;
end
[M, N] = size(squareMatrix);
if (M ~= N)
disp('Error on input. Only accepts a square matrix as input.');
return;
end
diagSum = zeros(1, M+N-1);
if LLUR0_ULLR1 == 1
squareMatrix = rot90(squareMatrix, -1);
end
for i = 1:length(diagSum)
if i <= M
countUp = 1;
countDown = i;
while countDown ~= 0
diagSum(i) = squareMatrix(countUp, countDown) + diagSum(i);
countUp = countUp+1;
countDown = countDown-1;
end
end
if i > M
countUp = i-M+1;
countDown = M;
while countUp ~= M+1
diagSum(i) = squareMatrix(countUp, countDown) + diagSum(i);
countUp = countUp+1;
countDown = countDown-1;
end
end
end
Cheers