I have sparse matrix A which I need to convert to complex-sparse matrix by setting its imaginary part to zero.
A = sprand(3,3,0.5);
A_c = complex(A,0);
However, this throws me an error that A should be full.
Error using complex
Real input A must be numeric, real, and full.
Is there any work-around to achieve this?
When I first answered this question I did not consider the way complex sparse matrices are implemented in MATLAB. I tricked myself into the following answer.
Naive solution
You could apply complex() to each element of the matrix.
A_c = spfun(#(x)complex(x,0),A)
Here #(x)complex(x,0) denotes an anonymous function that applied to each element x of the matrix A returns a complex number with Re=x and Im=0. And spfun just returns a new sparse matrix produced by applying our anonymous function to the nonzero elements of the matrix A.
What happens is that this solution returns an object identical to the original matrix. The matrix A_c occupies the same number of bytes and is equal to the original matrix A.
>> whos A A_c
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
A 3x3 76 double
A_c 3x3 76 double
A comment from Florian Roemer made me reconsider my answer.
Explanation
The representation of sparse matrices in MATLAB is described in a paper by Gilbert, Moler and Schreiber published in 1991.
A real matrix is represented as a single vector of nonzero elements of the corresponding storage class (i.e. double or complex) stored in column-wise order plus an integer vector of indices of these elements in their respective columns plus an integer vector of indices of locations where new columns start. I.e. an m*n sparse matrix with k nonzero elements would occupy n*4 + k*12 bytes with 4 bytes for integers and 8 bytes to store reals as double precision. That is a 3x3 real sparse matrix with 5 nonzero entries occupies (4+5)*4+8*5 = 76 bytes.
A complex sparse matrix would have another real array for the imaginary parts of all nonzero entries of the matrix but only if at least one element has a nonzero imaginary part.
Consider
>> B = sprand(3,3,0.5)
B =
Compressed Column Sparse (rows = 3, cols = 3, nnz = 5 [56%])
(1, 1) -> 0.46883
....
>> B_c = B ; B_c(1,1) += 1e-100i
B_c =
Compressed Column Sparse (rows = 3, cols = 3, nnz = 5 [56%])
(1, 1) -> 4.6883e-01 + 1.0000e-100i
....
Now we have made MATLAB to allocate additional storage for the imaginary parts of each nonzero entry of the original matrix, even though only one of the entries has a nonzero imaginary part.
>> whos B B_c
Variables in the current scope:
Attr Name Size Bytes Class
==== ==== ==== ===== =====
B 3x3 76 double
c B_c 3x3 116 double
Now B_c is a proper complex sparse matrix that occupies
(4+5)*4 + 8 * 5 + 8 * 5 = 116 bytes
Conclusion
If you just need a sparse matrix with zero imaginary parts, then do nothing to the original matrix.
If you need a matrix that actually allocates storage for the complex entries and carries the complex attribute, then add a small imaginary value to at least one of the nonzero entries of the original matrix.
Matlab remark: I did not test this in actual Matlab but Octave is quite happy with this solution.
Related
I need to know if there is any efficient way of doing the following in MATLAB.
I have several big sparse matrices, the size of each one is roughly 9000000x9000000.
I need to access multiple element of such matrix and assign to each selected element a different value stored in another array. I'll give an example:
What I have:
SPARSE MATRIX of size 9000000x9000000
Matrix with the list of indexes and values I want to access, this is a matrix like this:
[row1, col1, value1;
row2, col2, value2;
...
rowN, colN, valueN]
Where N is the length of such matrix.
What I need:
Assign to the SPARSE MATRIX the corresponding value to the corresponding index, this is:
SPARSE_MATRIX(row1, col1) = value1
SPARSE_MATRIX(row2, col2) = value2
...
SPARSE_MATRIX(rowN, colN) = valueN
Thanks in advance!
EDIT:
Thank you to both for answering, I think I did not explain myself well, I'll try again.
I already have a large SPARSE MATRIX of about 9000000 rows x 9000000 columns, it is a SPARSE MATRIX filled with zeros.
Then I have another array or matrix, let's call it M with N number of rows, where N could take values from 0 to 9000000; and 3 columns. The first two columns are used to index an element of my SPARSE MATRIX, and the third column stores the value I want to transfer to the SPARSE MATRIX, this is, given a random row of M, i:
SPARSE_MATRIX(M(i, 1), M(i, 2)) = M(i, 3)
The idea is to do that for all the rows, I have tried it with common indexing:
SPARSE_MATRIX(M(:, 1), M(:, 2)) = M(:, 3)
Now I would like to do this assignation for all the rows in M as fast as possible, because if I use a loop or common indexing it takes ages (I am using a 7th Gen i7 processor with 16 GB of RAM). And I also need to keep the zeros in the SPARSE_MATRIX.
EDIT 2: SOLVED! Thank you Metahominid, I was not thinking through, but yes the sparse function does solve my problem, I just think my brain circuits were shortcircuited yesterday and was unable to see through it hahaha. Thank you to both anyway!
Regards!
You can construct a sparse matrix like this.
A = sparse(i,j,v)
S = sparse(i,j,v) generates a sparse matrix S from the triplets i, j,
and v such that S(i(k),j(k)) = v(k). The max(i)-by-max(j) output
matrix has space allotted for length(v) nonzero elements. sparse adds
together elements in v that have duplicate subscripts in i and j.
So you can simply construct the row vector, column vector and value vector.
I am answering in part because I cannot comment. You question seems a little confusing to me. The sparse() function in MATLAB does just this.
You can enter your arrays of indices and values directly into the interface, or declare a sparse matrix of zeros and set each individually.
Given your data format make three vectors, ROWS = [row1; ...; rown], COLS = [col1; ...; coln], and DATA = [val1; ... valn]. I am assuming that your size is the overall size of the full matrix and not the sparse portion.
Then
A = sparse(ROWS, COLS, DATA) will do just what you want. You can even specify the original matrix size.
A = sparse(ROWS, COLS, DATA, 90...., 90....).
I'm new to MATLAB and its development. I have a image which is 1134 (rows) X 1134 (columns). I want that image to save 3 (columns) X 3 (rows). In order to do that I need 378 cells. For that I used following code, but it gives me an error.
image=imread('C:\Users\ven\Desktop\test\depth.png');
I=reshape(image,1,1134*1134);
chunk_size = [3 3]; % your desired size of the chunks image is broken into
sc = sz ./ chunk_size; % number of chunks in each dimension; must be integer
% split to chunk_size(1) by chunk_size(2) chunks
X = mat2cell(I, chunk_size(1) * ones(sc(1),1), chunk_size(2) *ones(sc(2),1));
Error:
Error using mat2cell (line 97)
Input arguments, D1 through D2, must sum to each dimension of the input matrix size, [1 1285956].'
Unfortunately your code does not work as you think it would.
The ./ operator performs point wise division of two matrices. Short example:
[12, 8] ./ [4, 2] == [12/4, 8/2] == [3, 4]
In order for it to work both matrices must have exactly the same size. In your case you try to perform such an operation on a 1134x1134 matrix (the image) and a 1x2 matrix (chunk_size).
In other words you can not use it to divide matrices into smaller ones.
However, a solution to your problem is to use the mat2cell function to pick out subsets of the matrix. A explanation of how it is done can be found here (including examples): http://se.mathworks.com/matlabcentral/answers/89757-how-to-divide-256x256-matrix-into-sixteen-16x16-blocks.
Hope it helps :)
Behind the C=A./B command is loop over all elements of A(ii,jj,...) and B(ii,jj,..) and each C(ii,jj,..)=A(ii,jj,...)/B(ii,jj,...).
Therefore martices A and B must be of same dimension.
If you want to split matrix into groups you can use
sc=cell(1134/3,1);
kk=0;ll=0;
for ii=2:3:1133
kk=kk+1;
for jj=2:3:1133
ll=ll+1;
sc{kk,ll}=image(ii-1:ii+1,jj-1:jj+1);
end
end
The code allocates cell array sc for resulting submatrices and arbitrary counters kk and ll. Then it loops over ii and jj with step of 3 representing centers of each submatrices.
Edit
Or you can use mat2cell command (type help mat2cell or doc mat2cell in matlab shell)
sc=mat2cell(image,3,3);
In both cases the result is cell array and its iith and jjth elements (matrices) are accessible by sc{ii,jj}. If you want call iith anr jjth number in kkth and llth matrix, do it via sc{kk,ll}(ii,jj).
In short, you divided a 1134 x 1134 by 2 x 1 matrix. That doesn't work.
The error "Matrix dimensions must agree**" is from the dividing a matrix with another matrix that doesn't have the right dimensions.
You used the scalar divide "./" which divided a matrix by another matrix.
You want something like:
n = 1134 / 3 % you should measure the length of the image
I1=image(1:n,1:n); % first row
I2=image(1:n,n:2n);
I3=image(1:n,2n:3n);
I4=image(n:2n,1:n); % second row
I5=image(n:2n,n:2n);
I6=image(n:2n,2n:3n);
I7=image(2n:3n,1:n); % third row
I8=image(2n:3n,n:2n);
I9=image(2n:3n,2n:3n);
from here:
http://au.mathworks.com/matlabcentral/answers/46699-how-to-segment-divide-an-image-into-4-equal-halves
There would be a nice loop you could do it in, but sometimes thinking is hard.
This question already has answers here:
Find specific value's count in a vector
(4 answers)
Closed 8 years ago.
I have a NxM matrix for example named A. After some processes I want to count the zero elements.
How can I do this in one line code? I tried A==0 which returns a 2D matrix.
There is a function to find the number of nonzero matrix elements nnz. You can use this function on a logical matrix, which will return the number of true.
In this case, we apply nnz on the matrix A==0, hence the elements of the logical matrix are true, if the original element was 0, false for any other element than 0.
A = [1, 3, 1;
0, 0, 2;
0, 2, 1];
nnz(A==0) %// returns 3, i.e. the number of zeros of A (the amount of true in A==0)
The credits for the benchmarking belong to Divarkar.
Benchmarking
Using the following paramters and inputs, one can benchmark the solutions presented here with timeit.
Input sizes
Small sized datasize - 1:10:100
Medium sized datasize - 50:50:1000
Large sized datasize - 500:500:4000
Varying % of zeros
~10% of zeros case - A = round(rand(N)*5);
~50% of zeros case - A = rand(N);A(A<=0.5)=0;
~90% of zeros case - A = rand(N);A(A<=0.9)=0;
The results are shown next -
1) Small Datasizes
2. Medium Datasizes
3. Large Datasizes
Observations
If you look closely into the NNZ and SUM performance plots for medium and large datasizes, you would notice that their performances get closer to each other for 10% and 90% zeros cases. For 50% zeros case, the performance gap between SUM and NNZ methods is comparatively wider.
As a general observation across all datasizes and all three fraction cases of zeros,
SUM method seems to be the undisputed winner. Again, an interesting thing was observed here that the general case solution sum(A(:)==0) seems to be better in performance than sum(~A(:)).
some basic matlab to know: the (:) operator will flatten any matrix into a column vector , ~ is the NOT operator flipping zeros to ones and non zero values to zero, then we just use sum:
sum(~A(:))
This should be also about 10 times faster than the length(find... scheme, in case efficiency is important.
Edit: in the case of NaN values you can resort to the solution:
sum(A(:)==0)
I'll add something to the mix as well. You can use histc and compute the histogram of the entire matrix. You specify the second parameter to be which bins the numbers should be collected at. If we just want to count the number of zeroes, we can simply specify 0 as the second parameter. However, if you specify a matrix into histc, it will operate along the columns but we want to operate on the entire matrix. As such, simply transform the matrix into a column vector A(:) and use histc. In other words, do this:
histc(A(:), 0)
This should be equivalent to counting the number of zeroes in the entire matrix A.
Well I don't know if I'm answering well the question but you could code it as follows :
% Random Matrix
M = [1 0 4 8 0 6;
0 0 7 4 8 0;
8 7 4 0 6 0];
n = size(M,1); % Number of lines of M
p = size(M,2); % Number of columns of M
nbrOfZeros = 0; % counter
for i=1:n
for j=1:p
if M(i,j) == 0
nbrOfZeros = nbrOfZeros + 1;
end
end
end
nbrOfZeros
I am trying to find the largest vector inside a matrix compound by vectors with MATLAB, however I am having some difficulties, so I would be very thankful if someone help me. I have this:
The matrix paths (solution of a Dijkstra function), which is a 1000x1000 matrix, whose values are vectors of 1 row and different number of columns (when the columns are bigger than 10, the values appear as "1x11 double, 1x12 double, etc"). The matrix paths have this form:
1 2 3 ....
1 1 <1x20 double> <1x16 double>
2 <1x20 double> 2 [2,870,183,492,641,863,611,3]
3 <1x16 double> [3,611,863,641,492,183,870,2] 3
4 <1x25 double> <1x12 double> <1x14 double>
.
.
.
At first I thought in just finding the largest vector in the matrix by
B = max(length(paths))
However MATLAB returns B = 1000, value which is feasible, but not likely. When trying to find out the position of the vector by using:
[row,column] = find(length(paths) == B)
MATLAB returns row = 1, column = 1, which for sure is wrong... I have thought that maybe is a problem of how MATLAB takes the data. It is like it doesn't consider the entries of the matrix as vectors, because when I enter:
length(paths(3,2))
It returns me 1, but it should return 8 as I understand, also when introducing:
paths(3,2)
It returns [1x8 double] but I expect to see the whole vector. I don't know what to do, maybe a "for" loop, I really do not know if MATLAB takes the data of the matrix as vectors or as simple double values.
The cell with the largest vector can be found using cellfun and numel to get the number of elements in each numeric matrix stored in the cells of paths:
vecLens = cellfun(#numel,paths);
[maxLen,im] = max(vecLens(:));
[rowMax,colMax] = ind2sub(size(vecLens),im)
This gets a 1000x1000 numeric matrix vecLens containing the sizes, max gets the linear index of the largest element, and ind2sub translates that to row,column indexes.
A note on length: It gives you the size of the largest dimension. The size of paths is 1000x1000, so length(paths) is 1000. My advice is, Don't ever use length. Use size, specifying the dimension you want.
If multiple vectors are the same length, you get the first one with the above approach. To get all of them (starting after the max command):
maxMask = vecLens==maxLen;
if nnz(maxMask)>1,
[rowMax,colMax] = find(maxMask);
else
[rowMax,colMax] = ind2sub(size(vecLens),im)
end
or just
[rowMax,colMax] = find(vecLens==maxLen);
I am currently trying to code up a function to assign probabilities to a collection of vectors using a histogram count. This is essentially a counting exercise, but requires some finesse to be able to achieve efficiently. I will illustrate with an example:
Say that I have a matrix X = [x1, x2....xM] with N rows and M columns. Here, X represents a collection of M, N-dimensional vectors. IN other words, each of the columns of X is an N-dimensional vector.
As an example, we can generate such an X for M = 10000 vectors and N = 5 dimensions using:
X = randint(5,10000)
This will produce a 5 x 10000 matrix of 0s and 1s, where each column is represents a 5 dimensional vector of 1s and 0s.
I would like to assign a probability to each of these vectors through a basic histogram count. The steps are simple: first find the unique columns of X; second, count the number of times each unique column occurs. The probability of a particular occurrence is then the #of times this column was in X / total number of columns in X.
Returning to the example above, I can do the first step using the unique function in MATLAB as follows:
UniqueXs = unique(X','rows')'
The code above will return UniqueXs, a matrix with N rows that only contains the unique columns of X. Note that the transposes are due to weird MATLAB input requirements.
However, I am unable to find a good way to count the number of times each of the columns in UniqueX is in X. So I'm wondering if anyone has any suggestions?
Broadly speaking, I can think of two ways of achieving the counting step. The first way would be to use the find function, though I think this may be slow since find is an elementwise operation. The second way would be to call unique recursively as it can also provide the index of one of the unique columns in X. This should allow us to remove that column from X and redo unique on the resulting X and keep counting.
Ideally, I think that unique might already be doing some counting so the most efficient way would probably be to work without the built-in functions.
Here are two solutions, one assumes all values are either 0's or 1's (just like the example in your description), the other does not. Both codes should be very fast (more so the one with binary values), even on large data.
1) only zeros and ones
%# random vectors of 0's and 1's
x = randi([0 1], [5 10000]); %# RANDINT is deprecated, use RANDI instead
%# convert each column to a binary string
str = num2str(x', repmat('%d',[1 size(x,1)])); %'
%# convert binary representation to decimal number
num = (str-'0') * (2.^(size(s,2)-1:-1:0))'; %'# num = bin2dec(str);
%# count frequency of how many each number occurs
count = accumarray(num+1,1); %# num+1 since it starts at zero
%# assign probability based on count
prob = count(num+1)./sum(count);
2) any positive integer
%# random vectors with values 0:MAX_NUM
x = randi([0 999], [5 10000]);
%# format vectors as strings (zero-filled to a constant length)
nDigits = ceil(log10( max(x(:)) ));
frmt = repmat(['%0' num2str(nDigits) 'd'], [1 size(x,1)]);
str = cellstr(num2str(x',frmt)); %'
%# find unique strings, and convert them to group indices
[G,GN] = grp2idx(str);
%# count frequency of occurrence
count = accumarray(G,1);
%# assign probability based on count
prob = count(G)./sum(count);
Now we can see for example how many times each "unique vector" occurred:
>> table = sortrows([GN num2cell(count)])
table =
'000064850843749' [1] # original vector is: [0 64 850 843 749]
'000130170550598' [1] # and so on..
'000181606710020' [1]
'000220492735249' [1]
'000275871573376' [1]
'000525617682120' [1]
'000572482660558' [1]
'000601910301952' [1]
...
Note that in my example with random data, the vector space becomes very sparse (as you increase the maximum possible value), thus I wouldn't be surprised if all counts were equal to 1...