Generate derived matrix from index vector in matlab - matlab

Consider an index vector consisting of ones and zeros:
I=[0 0 1 0 1 1 0 0 0];
How can I easily generate the following matrix in matlab:
J=[0 2;
1 1;
0 1;
1 2;
0 3];

Use diff:
I = [0 0 1 0 1 1 0 0 0];
d = diff(I);
ind = [1 find(d~=0)+1]; %// starting index of each new value
rep = diff([ind numel(I)+1]); %// number of repetitions of each new value
J = [ I(ind).' rep.' ];

Using strfind for a slightly bigger example -
I =[1 1 0 0 1 0 1 1 0 0 0 1 1 1 1 0 0]
zero_pos = ['0' num2str(bsxfun(#eq,I,0),'%1d') '0']
ind3 = [ strfind(zero_pos,'01') ; strfind(zero_pos,'10')]
counts = diff(ind3(:))
var = zeros(numel(counts),1);
var(2:2:end)=1;
J = [var counts];
if ind3(1,1)-1>0
J = [1 ind3(1,1)-1;J];
end
Output
J =
1 2
0 2
1 1
0 1
1 2
0 3
1 4
0 2

Related

How to crate cells contain subvectors from logical vector in MATLAB

For example I have a logial vector in MATLAB:
idx1 = [0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0]
And I want to get numbers (count each block) of such blocks: 1 1 1, i.e. such block contain N elements == 1 (N "1"). idx1 - array, and his dimension can be any, for example 3820000.
How count many blocks (sequences of ones) occur in the entire array idx1?
counts_idx = 0;
init_counts_idx = 0;
arr = 0;
for i = 1:length(idx1) -1
for kk = 1 : length(idx1) - 1
if idx1(kk + 1) == 1
init_counts_idx = init_counts_idx + 1;
arr = init_counts_idx;
else
init_counts_idx = counts_idx;
end
C = {i,arr};
end
end
I try to using cells...
You can calculate the start and end indices of each block by diff([0 idx1 0]). Then, use this information to calculate block lengths Ns. Finally express the result as a cell array using the function C = mat2cell(A,rowDist).
idx1 = [0 0 0 1 1 1 0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 1 0 0];
diffs = diff([0 idx1 0]);
% find start index of the blocks
loc = find(diffs == 1);
% calc block lengths by subtracting end - start indices
Ns = find(diffs == -1) - loc;
C = mat2cell([loc' Ns'],ones(size(loc)))
4×1 cell array
{[ 4 3]}
{[ 9 3]}
{[16 6]}
{[29 3]}
If you are interested only in the number of such blocks, length(loc) will give you the answer, it is similar to bwconncomp(idx1).NumObjects.
bwconncomp(idx1).NumObjects
See bwconncomp()

Spread elements of rows to multiple rows

I am working on graph theory using adjacency matrix, I want to split the edges between multiple nodes for instance I have the following initial adjacency matrix :
a= [ 0 2 3;
2 0 1;
3 1 0]
From that matrix its clear that we have 3 nodes, Now I want to split the aforementioned rows (edges) into new random nodes between (1-3) :
split= randi([1 3],1,length(A));
split = [ 2 2 1]
I know now that I need to split the elements of the first row into two rows, the elements of the second rows also into two rows, while the elements of th third row will remain as is, and I'll have new matrix with size 5X5 as following:
A = [0 0 2 0 3;
0 0 0 0 0;
2 0 0 0 1;
0 0 0 0 0;
3 0 1 0 0]
What I want to do is to split the non-zero elements in the first row between this row and the second row, and the third with the fourth, so my matrix will look like:
An = [0 0 2 0 0;
0 0 0 0 3;
2 0 0 0 0;
0 0 0 0 1;
0 3 0 1 0]
It's not fully clear to me what's the initial point, the prerequisites and conditions. I assume that every second row/column is a row/column of zeros. I furthermore assume that the non-zero rows/columns have exactly two non-zero values whereas the second value should be moved to the next row/column. For this, I'd suggest:
A = [0 0 2 0 3 ; 0 0 0 0 0 ; 2 0 0 0 1 ; 0 0 0 0 0 ; 3 0 1 0 0];
for n = 1:2
if n==2
A = A';
end % if
for k = 1:2:size(A,1)-1
m = find(A(k,:));
A(k+(0:1),m(end)) = flipud(A(k+(0:1),m(end)));
end % for
if n==2
A = A';
end % if
end % for
A
A =
0 0 2 0 0
0 0 0 0 3
2 0 0 0 0
0 0 0 0 1
0 3 0 1 0
Here An is directly generated from a without creating A:
a = [ 0 2 3;
2 0 1;
3 1 0];
split = [ 2 2 1];
L = length(a);
cum = cumsum([1 split(1:end-1)]);
%ro = rot90(split - (0:L-1).' + cum-1, -1); %MATLAB R2016b
ro = rot90(bsxfun(#minus,split + cum-1 , (0:L-1).') , -1);
co = repmat(cum, L, 1);
idx = triu(true(L), 1);
N = sum(split);
An = zeros(N);
sub = sub2ind([N,N], ro(idx), co(idx));
An(sub) = a(idx);
An = An + An.'
An =
0 0 2 0 0
0 0 0 0 3
2 0 0 0 0
0 0 0 0 1
0 3 0 1 0

How to replace duplicate elements as 0 in column matrix in matlab

I need to replace the repeated elements in column of a matrix as 0's and delete the rows which has all 0's. If my matrix is like this means.
Input =
1 0 0 1
0 1 0 1
0 0 1 1
1 1 1 1
My expected output should be like this
Output =
1 0 0 1
0 1 0 0
0 0 1 0
0 0 0 0 ---> this row should be get deleted in this case
This doesn't work for my problem
c = [ 1 1 0 1 0 1 1 1 0 1 1 0];
[c, ic] = unique(a, 'first');
c(~ismember(1:length(a),ic)) = 0;
You can use logical indexing and cumsum:
A = [1 0 0 1;
0 1 0 1;
0 0 1 1;
1 1 1 1];
ind = cumsum(A); %cumulative sum (by column)
A(ind>1) = 0;
A(sum(A')==0,:)=[]

Iteratively and randomly adding ones to a binary vector in matlab

In each iteration I want to add 1 randomly to binary vector,
Let say
iteration = 1,
k = [0 0 0 0 0 0 0 0 0 0]
iteration = 2,
k = [0 0 0 0 1 0 0 0 0 0]
iteration = 3,
k = [0 0 1 0 0 0 0 1 0 0]
, that goes up to length(find(k)) = 5;
Am thinking of for loop but I don't have an idea how to start.
If it's important to have the intermediate vectors (those with 1, 2, ... 4 ones) as well as the final one, you can generate a random permutation and, in your example, use the first 5 indices one at a time:
n = 9; %// number of elements in vector
m = 5; %// max number of 1's in vector
k = zeros(1, n);
disp(k); %// output vector of all 0's
idx = randperm(n);
for p = 1:m
k(idx(p)) = 1;
disp(k);
end
Here's a sample run:
0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 1
1 0 0 0 0 0 0 0 1
1 0 0 1 0 0 0 0 1
1 0 0 1 1 0 0 0 1
1 1 0 1 1 0 0 0 1
I wouldn't even use a loop. I would generate a random permutation of indices that sample from a vector going from 1 up to the length of k without replacement then just set these locations to 1. randperm suits the task well:
N = 10; %// Length 10 vector
num_vals = 5; %// 5 values to populate
ind = randperm(N, num_vals); %// Generate a vector from 1 to N and sample num_vals values from this vector
k = zeros(1, N); %// Initialize output vector k to zero
k(ind) = 1; %// Set the right values to 1
Here are some sample runs when I run this code a few times:
k =
0 0 1 1 0 1 1 0 0 1
k =
1 0 0 0 1 0 1 1 0 1
k =
1 0 0 0 1 0 1 1 0 1
k =
0 1 1 1 0 0 1 0 0 1
However, if you insist on using a loop, you can generate a vector from 1 up to the desired length, randomly choose an index in this vector then remove this value from the vector. You'd then use this index to set the location of the output:
N = 10; %// Length 10 vector
num_vals = 5; %// 5 values to populate
vec = 1 : N; %// Generate vector from 1 up to N
k = zeros(1, N); %// Initialize output k
%// Repeat the following for as many times as num_vals
for idx = 1 : num_vals
%// Obtain a value from the vector
ind = vec(randi(numel(vec), 1));
%// Remove from the vector
vec(ind) = [];
%// Set location in output to 1
k(ind) = 1;
end
The above code should still give you the desired effect, but I would argue that it's less efficient.

How to generate a matrix of vector combinations with zeros for excluded elements?

I want to create a matrix from all combinations of elements of one vector that fulfill a condition
For example, I have this vector
a = [1 2 3 4 5]
and want to create a matrix like
a = [1 0 0 0 0;
1 2 0 0 0;
1 2 3 0 0;
1 2 3 4 0;
1 2 3 4 5;
0 2 0 0 0;
0 2 3 0 0;
........;]
and then get the rows that fulfill the condition I can use the command:
b = sum(a')' > value
but I don't know how to generate the matrix
You can generate all possible binary combinations to determine the matrix you want:
a = [1 2 3];
n = size(a,2);
% generate bit combinations
c =(dec2bin(0:(2^n)-1)=='1');
% remove first line
c = c(2:end,:)
n_c = size(c,1);
a_rep = repmat(a,n_c,1);
result = c .* a_rep
Output:
c =
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
result =
0 0 3
0 2 0
0 2 3
1 0 0
1 0 3
1 2 0
1 2 3