Matlab Sparse Array Index Reassignment - arrays

Does anyone know if there is a way to do a simple reordering of the row-column positions in a sparse array in Matlab?
I have a sparse array which corresponds to the adjacency matrix of a graph that I am trying to analyze, and I would like to reorder the vertices in my graph by some calculated metric (while hopfully preserving the way that the mapping was constructed)
Does anyone have any suggestions on a way to do this? I am new to Matlab and am not yet completely familiar with all of the tools that it has for Matrix manipulations.

With a sparse matrix you assign entry values the same way as you would with a normal matrix. For example:
>> a = sparse(1:2, 3:4, [1 1], 4, 5, 7)
a =
(1,3) 1
(2,4) 1
a(1,3) = 0; a(1,2) = 1; % move the "1" from (1,3) to (1,2)
>> a
a =
(1,2) 1
(2,4) 1
You can also assign whole columns or rows. For example, this swaps columns 2 and 3:
aux = a(:,3);
a(:,3) = a(:,2);
a(:,2) = aux;

Related

Create all possible n-tuples from n vectors in Matlab, ordered in a specific way

Consider n row vectors in Matlab, each of size 1xU. For example,
U=20;
n=3;
sU=[U U U];
vectors = arrayfun(#(x) {1:x}, sU);
where vector{1} is the first row vector, vector{2} is the second row vector,..., vector{n} is the last row vector.
We create the matrix Tcoord of size U^n x n reporting all the possible n-tuples from the n row vectors. For each row i of Tcoord, Tcoord(i,1) is an element of the first row vector, Tcoord(i,2) is an element of the second row vector, ... , Tcoord(i,n) is an element of the last row vector.
Tcoord_temp = cell(1,n);
[Tcoord_temp{:}] = ndgrid(vectors{:});
Tcoord_temp = cat(n+1, Tcoord_temp{:});
Tcoord = reshape(Tcoord_temp,[],n);
Suppose now that I augment each of the n row vectors of 3 elements. For example,
vectors_augmented{1}=[vectors{1} 8 9 10];
vectors_augmented{2}=[vectors{2} 11 12 13];
vectors_augmented{3}=[vectors{3} 14 15 16];
I then create a matrix similar to Tcoord but now using vectors_augmented.
Tcoord_temp = cell(1,n);
[Tcoord_temp{:}] = ndgrid(vectors_augmented{:});
Tcoord_temp = cat(n+1, Tcoord_temp{:});
Tcoord_augmented = reshape(Tcoord_temp,[],n); %(U+3)^nxn
I would like your help to re-order the rows of the matrix Tcoord_augmented in a matrix Tcoord_augmented_reshape such that
Tcoord_augmented_reshape(1:U^n,:) is equal to Tcoord.
The remaining rows of Tcoord_augmented_reshape contains the other left rows of Tcoord_augmented.
The simplest approach is to build an auxiliary zero-one matrix the same size as Tcoord_augmented and sort rows based on that:
aug_size = [3 3 3]; % augment size of each vector. Not necessarily equal
vectors_aux = arrayfun(#(a) {[false(1,U) true(1, a)]}, aug_size);
T_aux = cell(1,n);
[T_aux{:}] = ndgrid(vectors_aux{:});
T_aux = cat(n+1, T_aux{:});
T_aux = reshape(T_aux,[],n);
[~, ind] = sortrows(T_aux, n:-1:1); % indices of stably sorting the rows.
% Most significant column is rightmost, as per your code
Tcoord_augmented_reorder = Tcoord_augmented(ind, :);

How to create a dynamic array in MATLAB

Description of this array:
10 dimensions, which represent 10 clusters.
Each dimension's length is not fixed, and should be zero at first.
After clustering, one coordinate (x,y) will be assigned to the corresponding cluster.
Example:
If (1,1) belongs to cluster 10, (2,2) belongs to cluster 9, and given a sequence of coordinates
(1,1) (1,1) (1,1) (1,1) (1,1) (2,2)
then A(1) to A(8) have no element while A(9) has 1 element with value (2,2) and A(10) has 5 elements with value (1,1).
I tried to use cell array, and I "kind of" get one, here is my code.
A = cell(10,0)
%create empty cell array
A(10,end+1) = {[1,1]}
%assign (1,1) to cluster 10
So now A is:
Then suppose we have (2,2) and it should assigned to A(9)
A(9,end) = {[2,2]}
Looks fine, but then if we assign (1,1) to A(10) again,
A(10,end) = {[1,1]}
Then the length is still the same and A(1) to A(8) are not empty!
My question is, is there any other method that can help me to create a dynamic array?
In MATLAB, we'll often store multiple coordinates into a single array, such that p(3,:) is the 3rd point. [One of the reasons for this is that this is a much more efficient way of storing data, as each array has an overhead, and storing many points as individual arrays within a e.g. cell array therefore is very wasteful of memory.]
I would suggest you use that method to store coordinates within each cluster. For example:
A = cell(10,1); % 10 clusters, we won't change the size of A
A{10}(end+1,:) = [1,1];
A{9}(end+1,:) = [2,2];
A{10}(end+1,:) = [1,1];
Now we can see what is inside A:
>> A{1}
ans =
[]
>> A{9}
ans =
2 2
>> A{10}
ans =
1 1
1 1
Note that A{10} is the contents of the cell (in this case a numeric array), whereas A(10) is a cell array with one cell.
A{10}(1,:) is the first coordinate in cluster 10. size(A{10},1) is the number of coordinates in cluster 10.
A{10}(end+1,:) = [1,1] is one way of appending an element. end+1 is a non-existing location, meaning the array will be extended to accommodate the new data assigned there. An alternative method is A{10} = [A{10} ; 1,1]. I'm not sure if these two methods are equivalent or not. In the case of a vector, or when appending a column, then the end+1 method is much more efficient, so I always recommend that method in all cases.
You need to create a cell array of cells.
Use repmat to create a 10 x 1 array of empty cells:
A = repmat({{}},10,1);
In order to access nested cells you need to chain indexes:
A{10}(end+1) = {[1,1]};
A{9} (end+1) = {[2,2]};
A{10}(end+1) = {[1,1]};
Or more simple indexing:
A{10}{end+1} = [1,1];
A{9} {end+1} = [2,2];
A{10}{end+1} = [1,1];
You should probably take a look at matlab's map https://www.mathworks.com/help/matlab/ref/containers.map.html
E.G. For your question:
A = containers.Map('KeyType','int32','ValueType','any');
A(9) = [2 2];
A(10) = [1 1;1 1;1 1;1 1;1 1];
Now A(9) has a vector with values (2,2) and A(10) has 10 row vectors with values (1,1).
You can retrieve the values the same way that you input the values:
>> A(9)
ans =
2 2
>> A(10)
ans =
1 1
1 1
1 1
1 1
1 1
Adding vectors to already defined keys:
>> A(9) = [A(9); 2 2];
>> A(9)
ans =
2 2
2 2

Return matrices of row and column indices

I am sure this question must be answered somewhere else but I can't seem to find the answer.
Given a matrix M, what is the most efficient/succinct way to return two matrices respectively containing the row and column indices of the elements of M.
E.g.
M = [1 5 ; NaN 2]
and I want
MRow = [1 1; 2 2]
MCol = [1 2; 1 2]
One way would be to do
[MRow, MCol] = find(ones(size(M)))
MRow = reshape(MRow, size(M))
MCol = reshape(MCol, size(M))
But this does not seem particular succinct nor efficient.
This essentially amounts to building a regular grid over possible values of row and column indices. It can be achieved using meshgrid, which is more effective than using find as it avoids building the matrix of ones and trying to "find" a result that is essentially already known.
M = [1 5 ; NaN 2];
[nRows, nCols] = size(M);
[MCol, MRow] = meshgrid(1:nCols, 1:nRows);
Use meshgrid:
[mcol, mrow] = meshgrid(1:size(M,2),1:size(M,1))

MATLAB: How to subset a multidimensional matrix using 1-D vector indices without for loops?

I am currently looking for an efficient way to slice multidimensional matrices in MATLAB. Ax an example, say I have a multidimensional matrix such as
A = rand(10,10,10)
I would like obtain a subset of this matrix (let's call it B) at certain indices along each dimension. To do this, I have access to the index vectors along each dimension:
ind_1 = [1,4,5]
ind_2 = [1,2]
ind_3 = [1,2]
Right now, I am doing this rather inefficiently as follows:
N1 = length(ind_1)
N2 = length(ind_2)
N3 = length(ind_3)
B = NaN(N1,N2,N3)
for i = 1:N1
for j = 1:N2
for k = 1:N3
B(i,j,k) = A(ind_1(i),ind_2(j),ind_3(k))
end
end
end
I suspect there is a smarter way to do this. Ideally, I'm looking for a solution that does not use for loops and could be used for an arbitrary N dimensional matrix.
Actually it's very simple:
B = A(ind_1, ind_2, ind_3);
As you see, Matlab indices can be vectors, and then the result is the Cartesian product of those vector indices. More information about Matlab indexing can be found here.
If the number of dimensions is unknown at programming time, you can define the indices in a cell aray and then expand into a comma-separated list:
ind = {[1 4 5], [1 2], [1 2]};
B = A(ind{:});
You can reference data in matrices by simply specifying the indices, like in the following example:
B = A(start:stop, :, 2);
In the example:
start:stop gets a range of data between two points
: gets all entries
2 gets only one entry
In your case, since all your indices are 1D, you could just simply use:
C = A(x_index, y_index, z_index);

Sorting a cell array of matrices based on numerical value in each matrix?

I am working on a coding project and ran into a roadblock. I have a cell array of 1x3 matrices. (1,1) encodes the value to sort by, (1,2) and (1,3) encode coordinates that i need for reference later. Is there any way to sort the cell array by the (1,1) values in each matrix within the larger cell array?
CombList = {[1,1,1], [5,1,2];
[4,1,3], [3,1,2];
[2,1,4], [2,1,3]};
I would like to sort by the first values in each matrix within the cell array. Ideally, it would return:
CombList = [1,1,1], [2,1,3];
[2,1,4], [3,1,2];
[4,1,3], [5,1,2]};
...once sorted:)
Thank you!
I believe the following should work. The result will be a numeric array, hope that will work for you.
CombList = {[1,1,1], [5,1,2];
[4,1,3], [3,1,2];
[2,1,4], [2,1,3]}
CombMat = cell2mat(CombList);
CombMat(:, 1:3) = sortrows(CombMat(:, 1:3));
CombMat(:, 4:6) = sortrows(CombMat(:, 4:6));
You can use mat2cell to get convert it back to a cell array, like this:
CombCell = mat2cell(CombMat, [1 1 1], [3 3])
Zany one-liner based on sortrows:
CombList = reshape(mat2cell(sortrows(cell2mat(reshape(CombList,[],1))),ones(numel(CombList),1),numel(CombList{1})),2,[]).';

Resources