How to iterate non-zeroes in a sparse matrix in Chapel - sparse-matrix

I have a matrix A still hanging around. It's large, sparse and new symmetric. I've created a sparse domain called spDom that contains the non-zero entries. Now, I want to iterate along row r and find the non-zero entries there, along with the index. My goal is to build another domain that is essentially row r's non-zeroes.

Here's an answer that will work with Chapel 1.15 as long as you're willing to store your sparse domain/array in CSR format:
First, I'll establish my (small, non-symmetric) sparse matrix for demonstration purposes:
use LayoutCS; // use the CSR/CSC layout module
config const n = 10; // declare problem size
const D = {1..n, 1..n}; // declare dense domain
var SD: sparse subdomain(D) dmapped CS(); // declare sparse subdomain
// populate sparse domain with some indices
SD += (1,1);
SD += (1,n/2);
SD += (2, n/4);
SD += (2, 3*n/4);
SD += (n/2, 1);
SD += (n/2, n);
var A: [SD] real; // declare sparse array
forall (i,j) in SD do // initialize sparse array values
A[i,j] = i + j/10.0;
My solution relies on an undocumented iterator on sparse CS* domains named dimIter() which can be used to iterate over the dimension that's stored consecutively in memory (so rows for CSR and columns for CSC). dimIter() takes two arguments: the dimension to iterate over (1=rows, 2=columns) and the index in the other dimension. Thus, to iterate over the rows that I've defined above, I could do:
for r in 1..n {
writeln("row ", r, " contains elements at:");
for c in SD.dimIter(2, r) do
writeln(" column ", c, ": ", A[r,c]);
}
For the sparse matrix I show above, this yields:
row 1 contains elements at:
column 1: 1.1
column 5: 1.5
row 2 contains elements at:
column 2: 2.2
column 7: 2.7
row 3 contains elements at:
row 4 contains elements at:
row 5 contains elements at:
column 1: 5.1
column 10: 6.0
row 6 contains elements at:
row 7 contains elements at:
row 8 contains elements at:
row 9 contains elements at:
row 10 contains elements at:
We're interested in generalizing the dimIter() iterator and making it part of the standard sparse domain/array interface, but haven't done so yet due to (a) questions about how to generalize it to n-dimensional sparse arrays and (b) questions about whether we need to support inefficient iteration directions (e.g., should one be able to iterate over columns of CSR or rows of CSC given the expense?)

Related

construct a matrix by removing different elements from an array without loops in matlab

Given a vector X of discrete positive integers with size 160*1, and a table Tb1 in size 40*200, that contains a list of indices to be deleted from X Each column from the 200 columns in Tb1 points to 40 elements to be deleted from original X.
I create a new matrix of the remaining 120*200 elements by using a for loop with 200 iterations, that at round i deletes 40 elements from a copy of the original X according to the indices listed in Tb1(:,i), but it takes too much time and memory.
How can I get the result without using loops and with a minimum number of operations?
Here are different methods:
Method1:
idx = ~hist(tbl, 1:160);
[f,~]=find(idx);
result1 = reshape(M(f),120,200);
Method2:
idx = ~hist(tbl, 1:160);
M2=repmat(M,200,1);
result2 = reshape(M2(idx),120,200);
Method 3 & 4:
% idx can be generated using accumarray
idx = ~accumarray([tbl(:) reshape(repmat(1:200,40,1),[],1)],true,[160,200],#any);
%... use method 1 and 2
Method5:
M5=repmat(M,200,1);
M5(bsxfun(#plus,tbl,0:160:160*199))=[];
result5 = reshape(M5,120,200);
Assuming that M is an array of integers and tbl is the table of indices.
It can be tested with the following data:
M = rand(160,1);
[~,tbl] = sort(rand(160,200));
tbl = tbl(1:40,:);
However it is more efficient if you generate indices of elements to be remained instead of indices of elements to be removed.

arrange rows according to common values present between the rows in an array in matlab

i have an array of 800 rows with 3 columns. I want to arrange it in such a way that the row coming after the first row contains at least 2 common values as the first and the next row after that one also contains at least 2 common values as the second.
Example; row 1 = 2 4 5 common row= row 30 = 2 5 13
so first arrangement;
2 4 5
2 5 13
the next row will be one common to the new row 2
example row 4= 13 45 5
therefore the arrangement will now be;
2 4 5
2 5 13
13 45 5
etc
currently, i have this code that groups those common together in cells and then displays them one after another. the problem with this is that the array contains more than one commonality.. for example, row 1 could have 2 rows that have a common value as it, this code brings all those rows together into one array and does the same for the second row.. how can i make the code i make the code do what i explained in the first paragraph;
here is the code;
% Data
A = connections;
% Engine
[m, n] = size(A);
groups =[];
ng = 0;
for k=1:m-1
u = unique(A(k,:)); % representation of kth row
[in, J] = ismember(A(k:end,:),u);
l = m-k+1;
r = repmat((1:l).', n, 1);
c = accumarray([r(in) J(in)],1,[l n]); % count
c = bsxfun(#min,c,c(1,:)); % clip
rows = sum(c,2)>=2; % check if at least 2 elements are common
rows(1) = false;
if any(rows)
ng = ng+1;
rows(1) = true;
groups = (k-1) + find(rows);
end
end
please note that the rest of the code below could be added only if groups was a cell array, bt it has been changed to be a normal array as written above.. so to test the code, there is no need to add the code below.
% Remove the tail
groups(ng+1:end) = [];
% Display
for k=1:1:length(groups)
gk = groups{k};
for r = gk'
fprintf('%d %d %d %d\n', r, A(r,:));
end
end
This is the Hamiltonian path problem. A Hamiltonian path or traceable path is a path that visits each vertex exactly once. Here you have 800 vertices (rows) each have one or more neighbors. The condition for neighborhood is that a vertex having 2 or more values common with other vertex.
to solve the problem You should create an adjacency matrix corresponding to the graph structure then finding an Hamiltonian path on the graph.
Here is a way to create the adjacency matrix:
[ m n] = size(A);
%generate all 2 element subsets of the set [1 2 3 ] to check if a row
% has two elemnts common with other row
x = nchoosek(1:n,2);
%generate indices for generating two element rows
col = repmat(x,m,1);
M = (1:m).';
row = kron(M,ones(size(x)));
IDX = sub2ind([m n] ,row, col);
%convert A with [m , 3] to a [(m * 3), 2)]matrix
% then sort each row to be comparable with other rows
B=sort(A(IDX),2);
%indices of rows that have two common elements is found
[~,I,II] = unique(B,'rows', 'first');
convert index of the [(m * 3), 2)]matrix to [m , 3] matrix
I = uint32(I-1) / n + 1;
%create adjacency matrix
adjacency= sparse(I(II(:)), M(II(:)),1,m,m);
%make the matrix symmetric
adjacency = adjacency | adjacency.';
% a vertex can not be neighbor of itself
adjacency(speye(m))=false;
You should implement your own version of the Hamiltonian path algorithm or find in the web.
However the Hamiltonian path problem can be converted to a special form of the travelling salesman problem by adding a vertex to the graph and making all other vertices neighbor to it.
So some changes should be applied to the adjacency matrix:
adjacency = [adjacency; ones(1,m)];
adjacency = [adjacency, ones(n+1,1)];
adjacency (end) = 0;
In Mathworks you can find an example that shows how to solve the travelling salesman problem using binary integer programming. However the method provided doesn't seems straightforward. So you may found other one or implement your own.

Adding multiple rows in Array

I have an array A size of 16X16 and I want to add first 3 rows out of 16 in A. What is the most efficient solution in MATLAB?
I tried this code but this is not efficient because I want to extend it for large arrays:
filename = 'n1.txt';
B = importdata(filename);
i = 1;
D = B(i,:)+ B(i+1,:)+ B(i+2,:);
For example, if I want to extend this for an array of size 256x256 and I want to extract 100 rows and add them, how I will do this?
A(1:3,:);%// first three rows.
This uses the standard indices of matrix notation. Check Luis's answer I linked for the full explanation on indices in all forms. For summing things:
B = A(1:100,:);%// first 100 rows
C = sum(B,1);%// sum per column
D = sum(B,2);%// sum per row
E = sum(B(:));%// sum all elements, rows and columns, to a single scalar

MATLAB pairwise differences in Nth dimension

Say i have a N-Dimensional matrix A that can be of any size. For example:
A = rand([2,5,3]);
I want to calculate all possible pairwise differences between elements of the matrix, along a given dimension. For example, if i wanted to calculate the differences along dimension 3, a shortcut would be to create a matrix like so:
B = cat(3, A(:,:,2) - A(:,:,1), A(:,:,3) - A(:,:,1), A(:,:,3) - A(:,:,2));
However, i want this to be able to operate along any dimension, with a matrix of any size. So, ideally, i'd like to either create a function that takes in a matrix A and calculates all pairwise differences along dimension DIM, or find a builtin MATLAB function that does the same thing.
The diff function seems like it could be useful, but it only calculates differences between adjacent elements, not all possible differences.
Doing my research on this issue, i have found a couple of posts about getting all possible differences, but most of these are for items in a vector (and ignore the dimensionality issue). Does anyone know of a quick fix?
Specific Dimension Cases
If you don't care about a general solution, for a dim=3 case, it would be as simple as couple lines of code -
dim = 3
idx = fliplr(nchoosek(1:size(A,dim),2))
B = A(:,:,idx(:,1)) - A(:,:,idx(:,2))
You can move around those idx(..) to specific dimension positions, if you happen to know the dimension before-hand. So, let's say dim = 4, then just do -
B = A(:,:,:,idx(:,1)) - A(:,:,:,idx(:,2))
Or let's say dim = 3, but A is a 4D array, then do -
B = A(:,:,idx(:,1),:) - A(:,:,idx(:,2),:)
Generic Case
For a Nth dim case, it seems you need to welcome a party of reshapes and permutes -
function out = pairwise_diff(A,dim)
%// New permuting dimensions
new_permute = [dim setdiff(1:ndims(A),dim)];
%// Permuted A and its 2D reshaped version
A_perm = permute(A,new_permute);
A_perm_2d = reshape(A_perm,size(A,dim),[]);
%// Get pairiwse indices for that dimension
N = size(A,dim);
[Y,X] = find(bsxfun(#gt,[1:N]',[1:N])); %//' OR fliplr(nchoosek(1:size(A,dim),2))
%// Get size of new permuted array that would have the length of
%// first dimension equal to number of such pairwise combinations
sz_A_perm = size(A_perm);
sz_A_perm(1) = numel(Y);
%// Get the paiwise differences; reshape to a multidimensiona array of same
%// number of dimensions as the input array
diff_mat = reshape(A_perm_2d(Y,:) - A_perm_2d(X,:),sz_A_perm);
%// Permute back to original dimension sequence as the final output
[~,return_permute] = sort(new_permute);
out = permute(diff_mat,return_permute);
return
So much for a generalization , huh!

Create a matrix from three column vectors

I have three column vectors, then I want to creat matrix from this column victors
A1(:);
A2(:);
A3(:)
each column vectors has 25 element then the new matrix C will be a matrix with 3x25
I want to make A1(:) the first column of matrix c
A2(:) second column
A3(:) third column
Use cat to concatenate along dimension 1 or 2 depending on how you input those three vectors.
Thus, you can use -
C = cat(2,A1(:),A2(:),A3(:)).'
Or
C = cat(1,A1(:).',A2(:).',A3(:).')
Of course, you can skip (:)'s, if you know that all those are column vectors.
The above two approaches assumes that you intend to get an output of size 3 x N, where is N is the number of elements in the column vectors. If you were looking to get an output of size N x 3 , i.e. where each column is formed from the elements of column vectors A1, A2 and so on, just drop the transpose from the first of the two approaches mentioned above. Thus, use this -
C = cat(2,A1(:),A2(:),A3(:))

Resources