Dividing complex shapes into contiguous sub-shapes in MATLAB - matlab

I have a 3D shape loaded into MATLAB as a 3D matrix. The matrix is fairly large, e.g. 250x250x250. The shape is defined within the matrix by numbers >0 but <=1, so all positive numbers in the matrix are "shape", and all zeros are "non-shape". The shape is contiguous. A simplified (8x8) example of one plane of such a shape is shown in below:
0 0 0 0 0 0 0 0
0 0 1 .5 .1 .2 1 0
0 0 0 0 0 .3 0 0
0 0 .2 .3 1 1 1 1
0 0 0 .8 1 0 0 0
0 .2 .1 1 0 1 0 0
0 .1 .9 .9 .9 0 0 0
0 0 0 0 0 0 0 0
I need to split this shape into 2 sub-shapes where the sum of values of the two sub-shapes is roughly equal, and where the two sub-shapes are contiguous. So a valid division could be [N.B. zeros replaced by '.' for visual clarity]:
. . . . . . . .
. . B B B B B .
. . . . . B . .
. . A A B B B B
. . . A A . . .
. A A A . A . .
. A A A A . . .
. . . . . . . .
But the following division would be invalid because not all of the values in sub-shape B can be directly joined up with each other.
. . . . . . . .
. . B B B A A .
. . . . . A . .
. . B B A A A A
. . . B A . . .
. B B B . A . .
. B B B B . . .
. . . . . . . .
My real-world example is in 3 dimensions and much larger. Any ideas how I could divide my shape into 2 contiguous sub-shapes. By extension, how can I divide it into 3 contiguous sub-shapes if I wanted to, again where the sum of values in the sub-shapes is approximately equal?

Related

create index into double table for quick access

I have a table as below:
1 2 3 4 5 6 . . . .
1 1 0 0 0 1 0 . . . .
2 0 0 1 1 1 1 . . . .
3 0 1 0 0 0 1 . . . .
4 1 0 0 0 0 0 . . . .
5 0 0 1 0 1 0 . . . .
. . . . . . . . . . .
. . .
. .
.
1,2,.... are title of rows and columns. I need to index into table this means that :
one array (vector) that index into row1 that is contain 1 (=column 1 because in table cell(1,1) is true). another array that index into row2 that is contain 3,4,5,6 (because cells (2,3),(2,4),(2,5),(2,6) are true) and etc ...
I read Compact MATLAB matrix indexing notation and Use a vector as an index to a matrix with accuracy but I can not write code for it work.
Since each of the result array is in different size, you could use cell array.
First your sample data is not really a table, so let's make an arbitrary one:
T = table({'a' 'a' 'a' 'b' 'b'}.',{'X' 'Y' 'Z' 'X' 'Z'}.',(1:5).',...
'VariableNames',{'UserId','productId','Rating'});
Next, we will convert all the 'key' columns to categorical arrays:
T.UserId = categorical(T.UserId);
T.productId = categorical(T.productId);
Then we use this categorical arrays to cross-tabulate the table:
cross_T = crosstab(T.UserId,T.productId)
And now we look for all the 1 in the new matrix:
[r,c] = find(cross_T);
And use an arrayfun to collect them by row:
% a function to return all 1 in row
row = #(x) c(r==x).';
% preform on all rows
r = arrayfun(row,1:size(cross_T,1),'UniformOutput',false).';
So we get as output the cell array r:
r =
[1x3 double]
[1x2 double]
And to look for the data on specific user we write:
>> r{2}
ans =
1 3
Is you want this to be more readable you can convert into structure array:
s = cell2struct(r,categories(T.UserId))
So then the output for s will be:
s =
a: [1 2 3]
b: [1 3]
Say you have the following matrix
>> A = randi([0,1], [5,5])
A =
1 0 1 1 1
1 0 1 0 1
1 1 1 1 0
0 1 1 0 1
0 0 0 1 0
you can find the vector for each row separately, by doing
>> find(A(1,:))
ans =
1 3 4 5
If you want to collect these vectors, you need to decide how in what kind of structure you want to collect them.

Create features (long vector) with scala

I have a Big CSV file (~2GB) that contains a parameter X that for each day has around 1000 record.
What I want to do is transform this column to a set features (vectors) of length 1000 (one for each day).
For example:
==> Day 1 Day P1
1 1
1 2
1 5
1 9
1 .
1 .
1 .
1 6
==> Day 2 1 4
2 1
2 2
2 5
2 7
2 .
2 .
2 .
2 8
Will be transformed to:
d1 1 2 5 9 . . . 6
d2 4 1 2 5 . . . 8
.
.
.
dn
How can I do that in Scala ?
I know that there will be issue with the memory, I'll try to store the result on multiple steps.
Here is what I've tried so far:
df_data.map(x => (x(1),x(3))).filter(x=> x._1== 1).zipWithIndex.map(x=> (x._1._1,(x._2,x._1._2))).groupByKey()
Now I get something like:
(1, (0,val1),(1,val2),(2,val3),...,(n,valn))

Set generation algorithm: Matlab

Consider the code :
clear all
N = 7;
Set = 1:N;
for i = 1:N-1
Set1 = nchoosek(Set,i);
[ L_Set1 , C_Set1] = size(Set1);
A = zeros( L_Set1,N-C_Set1);
ASS_R7 = zeros( L_Set1 , N+1 );
for i1 = 1:L_Set1
A(i1,:) = setdiff( 1:N , Set1(i1,:) );
ASS_R7(i1,:) = [ Set1(i1,:), 0 ,A(i1,:) ];
end
ASS_R(i) = {ASS_R7};
end
Here, ASS_R gives all the possible [ (N-k) 0 k ] sets where the elements are unique (and belong to [1,7].Also k>0).
I have been trying to generalize this code for all N<=7 and have not been able to come up with a solution.
To be more clear:
We get a cell array with cells of different sizes which look like this:
[ 1 2 3 4 5 6 0 7 ] . . . [ 1 0 2 3 4 5 6 7 ]
. .
{ . } . . . { . }
. .
[ 2 3 4 5 6 7 0 1 ] . . . [ 7 0 1 2 3 4 5 6 ]
However, I want all cells
[ 1 0 2 ] [ 1 0 2 3] [ 1 0 2 3 4 5 6 7 ]
. . .
{ . } . . { . } . . . { . }
. . .
[ 7 0 6 ] [ 7 0 6 5] [ 7 0 1 2 3 4 5 6 ]
[ 1 2 0 3 ] [ 1 2 0 3 4 5 6 7 ]
. .
{ . } . . . { . }
. .
[ 6 7 0 5 ] [ 6 7 0 1 2 3 4 5 ]
[ 1 2 3 4 5 6 0 7 ]
.
{ . }
.
[ 2 3 4 5 6 7 0 1 ]
Any ideas, guys?
Code
%%// Array of elements whose sets are to be formed
arr1 = 1:7;
%%// Get a size estimate of the final output cell array and initialize it
lim1 = cumsum(1:numel(arr1)-1);
outmat = cell(lim1(end),1);
%%// Get the cell array of sets, into outmat
cc1=1;
for k3 = 1:numel(arr1)-1
t1 = nchoosek(arr1,k3);
for k2=1:numel(arr1)-k3
mat1 =[];
for k1 = 1:size(t1,1)
t11 = t1(k1,:);
t2 = arr1(~ismember(arr1,t11));
t3 = nchoosek(t2,k2);
t4 = [repmat([t11 0],size(t3,1),1) t3];
mat1= [mat1; t4];
end
outmat(cc1)={mat1}; %%// Output
cc1 = cc1+1;
end
end

Octave generate combination subsets

Given a number N, I would like to create a matrix of x columns with every combination of a subset of N. For example, if N is 16 and x is 3 then I should get a matrix of 560 rows and each row will have 3 columns and contain a unique combination from the numbers 1 to 16.
Can I use a function zzz(N,x) ?
I will be generating a lot of them with different N and x values so a for loop will slow things down.
Just use the nchoosek function:
N = 16;
x = 3;
nchoosek(1:N, x)
returns 560 rows like this:
. . .
. . .
. . .
1 2 13
1 2 14
1 2 15
1 2 16
1 3 4
1 3 5
1 3 6
1 3 7
. . .
. . .
. . .

Extract matrix from existing matrix

I have written a code to generate a matrix with four columns to get all combinations of numbers whose sum is equal to 9 and each number varies from 0 to 9.
m = zeros(220, 4);
pd = 9;
i = 1;
for p = 0:1:pd
for q = 0:1:pd-p
for a = 0:1:pd-q-p
m(i,:) = [p, q, a, pd-a-q-p];
i = i+1;
end
end
end
m
Now i want filter the arrays with no zero, one zero, two zeros, three zeros. Like,
Three zero case
0 0 0 9
Two zero case
0 0 1 8
0 0 2 7
.
.
0 0 8 1
One zero case
0 1 1 7
0 1 2 6
.
.
.
0 7 1 1
and no zero case
1 1 1 6
1 1 2 5
.
.
6 1 1 1
and so on..
Any suggestions to do that or any alternative method ?
Update:
0 0 0 9
0 0 1 8
0 0 2 7
.
.
0 0 8 1
0 1 1 7
0 1 2 6
.
.
.
0 7 1 1
1 1 1 6
1 1 2 5
.
.
6 1 1 1
Any suggestions to get the matrix m in the above order?
This is the best I can do right now, and I haven't tested it on your entire input matrix
m(sum(m == 0, 2) == N, :)
should return the rows of m which contain N 0s.
EDIT: following your update, here's a suggestion for the complete code:
A = zeros(size(m));
k = 1;
for N = (size(m, 2) - 1):-1:0
rows = (sum(m == 0, 2) == N);
idx = k:k + sum(rows) - 1;
A(idx, :) = m(rows, :);
k = idx(end) + 1;
end
To sort by the number of leading zeros in a row, all you need is sortrows(m).
To sort by the total number of zeros in a row, use High Performance Mark's answer.
You can use the following function to get all rows of matrix A that have n zeros:
function rows = nzrows(A, n)
s = sum(A == 0, 2);
rows = A(s == n, :);
end
This is what I came up with:
zero_index =[];
one_index =[];
two_index =[];
three_index =[];
for i=1:size(m,1)
if(sum(m(i,:)==0)==0)
zero_index = [zero_index i];
end
if(sum(m(i,:)==0)==1)
one_index = [one_index i];
end
if(sum(m(i,:)==0)==2)
two_index= [two_index i];
end
if(sum(m(i,:)==0)==3)
three_index = [three_index i];
end
end
m(zero_index,:)
m(one_index,:)
m(two_index,:)
m(three_index,:)
Hope it helps.