Here's an interesting question :)
I have two "vectors of matrices" which I want to tile like the hankel function does for regular vertices.
For example:
Column Vector:
10
00
20
00
30
00
Row vector:
30 40 50 60
00 00 00 00
The resulting matrix needs to be:
10 20 30 40
00 00 00 00
20 30 40 50
00 00 00 00
30 40 50 60
00 00 00 00
Note that the 0 values can be changed, the resulting structure is the important part.
A related question:
I looked in the command "edit repmat" and saw some interesting syntax I couldn't find help for:
A=[1,3;2,4];
X=[1,1;2,2];
B=A(X,X);
and B ends up being
1 3 1 3
2 4 2 4
1 3 1 3
2 4 2 4
which is basically repmat(A,2,2);
So my question is, what is this syntax: A(X,X)?
Thanks a lot!
Ofer
If you want to tile a set of matrices the way HANKEL tiles values, here's one way you can do it. First, you can put all of your unique matrices in one cell array:
mat = [1 0; 0 0];
cArray = {mat 2.*mat 3.*mat 4.*mat 5.*mat 6.*mat}; %# Your 6 unique matrices
Now, if you want the first 3 matrices running down the first column and the last 4 matrices running across the last row, you can create an index matrix using HANKEL:
>> index = hankel(1:3,3:6);
index =
1 2 3 4
2 3 4 5
3 4 5 6
Then index your cell array with index and use CELL2MAT to convert the resulting cell array to one matrix:
>> cell2mat(cArray(index))
ans =
1 0 2 0 3 0 4 0
0 0 0 0 0 0 0 0
2 0 3 0 4 0 5 0
0 0 0 0 0 0 0 0
3 0 4 0 5 0 6 0
0 0 0 0 0 0 0 0
For the second part of your question, when you perform an indexing operation like A(X,Y), you are using the elements of X as row indices and the elements of Y as column indices into A. Every combination of values in X and Y is used. So, if X = [x1 x2 x3 x4] and Y = [y1 y2 y3 y4], then the result of B = A(X,Y) is equivalent to:
B = [A(x1,y1) A(x1,y2) A(x1,y3) A(x1,y4); ...
A(x2,y1) A(x2,y2) A(x2,y3) A(x2,y4); ...
A(x3,y1) A(x3,y2) A(x3,y3) A(x3,y4); ...
A(x4,y1) A(x4,y2) A(x4,y3) A(x4,y4)];
Related
I'd like to obtain all unique products for a given vector.
For example, given a:
a = [4,10,12,3,6]
I want to obtain a matrix that contains the results of:
4*10
4*12
4*3
4*6
10*12
10*3
10*6
12*3
12*6
3*6
Is there a short and/or quick way of doing this in MATLAB?
EDIT: a may contain duplicate numbers, giving duplicate products - and these must be kept.
Given:
a =
4 10 12 3 6
Construct the matrix of all pairwise products:
>> all_products = a .* a.'
all_products =
16 40 48 12 24
40 100 120 30 60
48 120 144 36 72
12 30 36 9 18
24 60 72 18 36
Now, construct a mask to keep only those values below the main diagonal:
>> mask = tril(true(size(all_products)), -1)
mask =
0 0 0 0 0
1 0 0 0 0
1 1 0 0 0
1 1 1 0 0
1 1 1 1 0
and apply the mask to the product matrix:
>> unique_products = all_products(mask)
unique_products =
40
48
12
24
120
30
60
36
72
18
If you have the Statistics Toolbox, you can abuse pdist, which considers only one of the two possible orders for each pair:
result = pdist(a(:), #times);
One option involves nchoosek, which returns all combinations of k elements out of a vector, each row is one combination. prod computes the product of rows or columns:
a = [4,10,12,3,6];
b = nchoosek(a,2);
b = prod(b,2); % 2 indicates rows
Try starting with this. Have the unique function filter out the result of multiplying a by itself.
b = unique(a*a')
I have a matrix 2000x5, in the first column the point number, and in columns 2-5 the 4 neighbours (0s if there isnt a neighbour). Is there an efficient way to create an adjacency matrix out of this ?
1 129 0 65 0
2 130 0 66 85
3 131 169 67 0
4 132 170 68 87
5 133 0 69 81
6 134 0 70 82
7 135 173 71 83
8 136 174 72 84
9 137 161 73 0
10 138 162 74 93
11 139 163 75 0
12 140 164 76 95
13 141 165 77 89
14 142 166 78 90
15 143 167 79 91
16 144 168 80 92
17 145 0 81 65
18 146 0 82 66
....
I found the following thread, where it is explained for just one neighbour, but I am not sure how to use it for multiple neighbours.
matlab adjacency list to adjacency matrix
I would very much appreciate any help.
A quick and simple technique:
adjMat = zeros(size(A,1));
for ind = 1:size(A,1)
% Flag 1 on each row 'ind' at the indices mentioned in col 2-5
adjMat(ind, nonzeros(A(ind,2:end))) = 1;
end
Since you have mentioned using the nearest neighbour search, it is likely that the adjacency list should be completely filled to result in a undirected graph, in the sense that if row 1 has 20 as a neighbour, row 20 very likely has 1 as a neighbour.
However technically speaking, this will produce an adjacency matrix exactly equivalent to the adjacency list, assuming nothing by itself.
Example:
For an adjacency list
A = [1 2 3; 2 0 1; 3 1 4; 4 5 3; 5 4 0]
A =
1 2 3
2 0 1
3 1 4
4 5 3
5 4 0
The result is:
adjMat =
0 1 1 0 0
1 0 0 0 0
1 0 0 1 0
0 0 1 0 1
0 0 0 1 0
P.S. To force undirected-ness, you can simply add another statement in the for loop body:
adjMat(nonzeros(A(ind,2:end)),ind) = 1;
This will ensure that the adjacency matrix will be symmetric, which is a characteristic of undirected graphs.
Firstly, I'm going to assume that the adjacency list is undirected. In any case, it's not that far of a stretch to go to multiple neighbours. What you need to do first is detect the total number of non-zero elements per row from columns 2 to 5. Once you do this, for the rows of the adjacency matrix, you would copy the point number for as many times as there are non-zero elements per that row. The function repelem is perfectly suitable to do that for you. The column indices would simply be the second to fifth columns removing all of the zero elements. How you can do this is first transpose the matrix resulting in indexing the second to fifth columns, then using a logical indexing matrix to remove out the zero entries. Doing this will unroll your vector in a column-major fashion, which is why transposing is required before doing this operation. Once you do this, you can create row and column access indices so that these can be input into sparse much like that post you linked.
Supposing that your matrix was stored in A, you would do something like this. This also assumes that each of the weights connecting the nodes are 1:
% Find total number of non-zero elements per row, skipping first column
non_zero = sum(A(:,2:end) ~= 0, 2);
% Create row indices
rows = repelem(A(:,1), non_zero);
% Create column indices
cols = A(:,2:end).';
cols = cols(cols ~= 0);
% Create adjacency matrix
adj = sparse([rows; cols],[cols; rows], 1);
The above representation is in sparse. If you want the full numeric version, cast the output using full:
adj = full(adj);
If your graph is directed
If you have a directed graph instead of an undirected graph, the above call to sparse duplicates edges so that you are creating links to and from each of the neighbours. If your graph is actually directed, then you simply have to only use the row and column indices once instead of twice as seen in the above code:
% Create adjacency matrix
adj = sparse(rows, cols , 1);
Test Case
Here's a small test case to show you that this works. Supposing my adjacency list looked like the following:
>> A = [1 0 2 3; 2 4 0 0; 3 0 0 4]
A =
1 0 2 3
2 4 0 0
3 0 0 4
The adjacency matrix is now:
>> full(adj)
ans =
0 1 1 0
1 0 0 1
1 0 0 1
0 1 1 0
Taking a look at the list above and how the matrix is populated, we can verify that this is correct.
Note about repelem
repelem assumes you have MATLAB R2015a or later. If you don't have this, you can consult this answer by user Divakar on a custom implementation of repelem here: Repeat copies of array elements: Run-length decoding in MATLAB
I have an array which looks similar to:
0 2 3 4 0 0 7 8 0 10
0 32 44 47 0 0 37 54 0 36
I wish to remove all
0
0
from this to get:
2 3 4 7 8 10
32 44 47 37 54 36
I've tried x(x == 0) = []
but I get:
x =
2 32 3 44 4 47 7 37 8 54 10 36
How can I remove all zero columns?
Here is a possible solution:
x(:,all(x==0))=[]
You had the right approach with x(x == 0) = [];. By doing this, you would remove the right amount of elements that can still form a 2D matrix and this actually gives you a vector of values that are non-zero. All you have to do is reshape the matrix back to its original form with 2 rows:
x(x == 0) = [];
y = reshape(x, 2, [])
y =
2 3 4 7 8 10
32 44 47 37 54 36
Another way is with any:
y = x(:,any(x,1));
In this case, we look for any columns that are non-zero and use these locations to index into x and extract out those corresponding columns.
Result:
y =
2 3 4 7 8 10
32 44 47 37 54 36
Another way which is more for academic purposes is to use unique. Assuming that your matrix has all positive values:
[~,~,id] = unique(x.', 'rows');
y = x(:, id ~= 1)
y =
2 3 4 7 8 10
32 44 47 37 54 36
We transpose x so that each column becomes a row, and we look for all unique rows. The reason why the matrix needs to have all positive values is because the third output of unique assigns unique ID to each unique row in sorted order. Therefore, if we have all positive values, then a row of all zeroes would be assigned an ID of 1. Using this array, we search for IDs that were not assigned a value of 1, and use those to index into x to extract out the necessary columns.
You could also use sum.
Sum over the columns and any column with zeros only will be zeros after the summation as well.
sum(x,1)
ans =
0 34 47 51 0 0 44 62 0 46
x(:,sum(x,1)>0)
ans =
2 3 4 7 8 10
32 44 47 37 54 36
Also by reshaping nonzeros(x) as follows:
reshape(nonzeros(x), size(x,1), [])
ans =
2 3 4 7 8 10
32 44 47 37 54 36
I'm fairly new to Matlab (and programming in general) and I can't figure out how to do this. Perhaps it is quite simple, but I could really use some help. I've got this matrix:
25 53 52 25 37
26 54 0 26 38
27 55 0 27 0
28 56 0 28 0
0 59 0 0 0
0 60 0 0 0
I would like to compute all different combinations, in terms of rows with one value from each column, like, 25,53,52,25,37 and 25,54,52,26,38 and 25,54,52,27,0 etc. Besides, I want to discard the combinations containing 0 (like 25,53,0,25,37).
Take a look at this function, allcombo([25:28],[53:56 59:60],52,[25:28],[37:38]) should be what you are looking for.
Adapted from this answer:
M = [ 25 53 52 25 37
26 54 0 26 38
27 55 0 27 0
28 56 0 28 0
0 59 0 0 0
0 60 0 0 0 ]; %// data matrix
[m n] = size(M);
C = mat2cell(M, m, ones(1,n)); %// convert to cell array of column vectors
combs = cell(1,n); %// pre-define to generate comma-separated list
[combs{end:-1:1}] = ndgrid(C{end:-1:1}); %// the reverse order in these two
%// comma-separated lists is needed to produce the rows of the result matrix in
%// lexicographical order
combs = cat(n+1, combs{:}); %// concat the n n-dim arrays along dimension n+1
combs = reshape(combs,[],n); %// result: each row gives a combination
This gives, in your example:
>> combs(1:5,:)
ans =
25 53 52 25 37
25 53 52 25 38
25 53 52 25 0
25 53 52 25 0
. . .
If any column has repeated entries, the result will have repeated rows. To keep only unique rows (note this changes the order of the rows):
combs = unique(combs,'rows');
I have some question. I have 2 matrix, it's have same size.
For example, first matrix :
1
1
0
0
1
0
Second matrix
34
56
12
12
33
14
Then, I want to compare this two matrix and groups it by the criteria on first matrix
so I will have this two groups matrix :
Matrix when the first matrix is have value 1
34
56
33
and
Matrix when the first matrix is have value 0
12
12
14
You could try this:
a = [1 1 0 0 1 0]';
b = [34 56 12 12 33 14]';
b(a==1)
b(a==0)