Im looking to create a matrix of rank k.
The dimension of the matrix is m x n. The input k satisfies that condition that k < min(m,n).
It's not really so clear what you are aiming for.
But in order to create a matrix B with specific rank k, from a matrix A (with rank at least k), you may like to utilize svd and proceed like:
>>> A= rand(7, 5);
>>> rank(A)
ans = 5
>>> [U, S, V]= svd(A);
>>> k= 3;
>>> B= U(:, 1: k)* S(1: k, 1: k)* V(:, 1: k)';
>>> rank(B)
ans = 3
Well, a trivial method is to produce a matrix that looks like:
1 0 0 0 0
0 1 0 0 0
0 0 1 1 1
0 0 0 0 0
i.e. k columns of the identity matrix, then repeat the last column n-k times (or m-k times, depending on orientation).
A matrix of rank 1 can be created by the outer product of two vectors, for example:
A = randn(10,1) * randn(1,10);
Add together k of these and you will have a matrix of rank k. Like this:
>> A = zeros(10);
>> for i = 1:4, A = A + randn(10,1) * randn(1,10); end
>> rank(A)
ans = 4
Related
I have the following matrix in Matlab:
M = [0 0 1
1 0 0
0 1 0
1 0 0
0 0 1];
Each row has exactly one 1. How can I (without looping) determine a column vector so that the first element is a 2 if there is a 1 in the second column, the second element is a 3 for a one in the third column etc.? The above example should turn into:
M = [ 3
1
2
1
3];
You can actually solve this with simple matrix multiplication.
result = M * (1:size(M, 2)).';
3
1
2
1
3
This works by multiplying your M x 3 matrix with a 3 x 1 array where the elements of the 3x1 are simply [1; 2; 3]. Briefly, for each row of M, element-wise multiplication is performed with the 3 x 1 array. Only the 1's in the row of M will yield anything in the result. Then the result of this element-wise multiplication is summed. Because you only have one "1" per row, the result is going to be the column index where that 1 is located.
So for example for the first row of M.
element_wise_multiplication = [0 0 1] .* [1 2 3]
[0, 0, 3]
sum(element_wise_multiplication)
3
Update
Based on the solutions provided by #reyryeng and #Luis below, I decided to run a comparison to see how the performance of the various methods compared.
To setup the test matrix (M) I created a matrix of the form specified in the original question and varied the number of rows. Which column had the 1 was chosen randomly using randi([1 nCols], size(M, 1)). Execution times were analyzed using timeit.
When run using M of type double (MATLAB's default) you get the following execution times.
If M is a logical, then the matrix multiplication takes a hit due to the fact that it has to be converted to a numerical type prior to matrix multiplication, whereas the other two have a bit of a performance improvement.
Here is the test code that I used.
sizes = round(linspace(100, 100000, 100));
times = zeros(numel(sizes), 3);
for k = 1:numel(sizes)
M = generateM(sizes(k));
times(k,1) = timeit(#()M * (1:size(M, 2)).');
M = generateM(sizes(k));
times(k,2) = timeit(#()max(M, [], 2), 2);
M = generateM(sizes(k));
times(k,3) = timeit(#()find(M.'), 2);
end
figure
plot(range, times / 1000);
legend({'Multiplication', 'Max', 'Find'})
xlabel('Number of rows in M')
ylabel('Execution Time (ms)')
function M = generateM(nRows)
M = zeros(nRows, 3);
col = randi([1 size(M, 2)], 1, size(M, 1));
M(sub2ind(size(M), 1:numel(col), col)) = 1;
end
You can also abuse find and observe the row positions of the transpose of M. You have to transpose the matrix first as find operates in column major order:
M = [0 0 1
1 0 0
0 1 0
1 0 0
0 0 1];
[out,~] = find(M.');
Not sure if this is faster than matrix multiplication though.
Yet another approach: use the second output of max:
[~, result] = max(M.', [], 1);
Or, as suggested by #rayryeng, use max along the second dimension instead of transposing M:
[~, result] = max(M, [], 2);
For
M = [0 0 1
1 0 0
0 1 0
1 0 0
0 0 1];
this gives
result =
3 1 2 1 3
If M contains more than one 1 in a given row, this will give the index of the first such 1.
i have the following vectors:
A=[1 0 1 0 0 1 0 1 0 0];
B=[1 2 3 4 5 6 7 8 9 10];
in this case A represents a time vector, where the 1s signal the beginning of one time unit.
now i want to add up all the values in B which correspond to a time unit with the same length of 3 steps.
So in this example this would mean the 3rd, 4th and 5th value and the 8th, 9th and 10th value of B should be summed cause these are in a time unit of length 3.
B_result=[12 27];
i know cumsum() is the command for this but i dont know how to say that only these specific values depending on the time indices of A should be summed.
can you help me?
thanks alot
You can use cumsum alongside accumarray and hist:
csa = cumsum(A); %// from begining og unit to unit indices
n = hist(csa, 1:max(csa)); %// count num of steps in each unit
B_result = accumarray( csa', B' ); %// accumulate B into different time units
B_result(n~=3) = []; %// discard all time units that do not have 3 steps
For a simpler pattern matching, you can use strfind:
loc = strfind([A,1],[1 0 0 1]); %// add the 1 at the end of A and the pattern to avoid longer intervals
idx = bsxfun(#plus,loc,(0:2)'); %'// get the indices that need to be summed
result = sum(B(idx),1); %// obtain the result
N = 3; %// We want to detect a one followed by exactly N-1 zeros. Call that
%// sequence an "interesting part"
ind = find([A 1]); %// find ones. Append a last one to detect a possible
%// interesting part at the end.
ind = ind(diff(ind)==N); %// index of beginning of interesting parts
cs = cumsum(B); %// accumulate values
B_result = cs(ind+N-1)-cs(ind-1); %// use index to build result
A more generic application of Jonas' Idea:
A = [1 0 1 0 0 1 0 1 0 0 0 0 1];
B = [1 2 3 4 5 6 7 8 9 10 11 12];
n = 3;
result = arrayfun(#(x) sum( B(x:x+n-1) ), strfind([A,1],num2str(10^n+1)-48))
or use cumsum instead of sum, I was not sure what you actually want:
result = arrayfun(#(x) cumsum( B(x:x+n-1) ), ...
strfind( [A,1],num2str(10^n+1)-48 ) ,'uni',0)
%optional:
result = cell2mat(result')
I want to run fast Matlab algorithms over Matrices by ignoring zero-elements.
In the past I just worked with a very slow double-for-loop e.g.
for i = 1 : size(x,1)
for j = 1 : size(x,2)
if x(i,j) ~= 0
... do something with x(i,j)
end
end
end
But how can I make the matrix operation on the whole matrix x?
E.g. how can I run
x(i,j) = log(x(i,j)) if x>0 else 0 <-- pseudo code
in Matlab on the whole matrix without for loops?
Finally I want to rewrite lines like
result = sum(sum((V.*log(V./(W*H))) - V + W*H));
with ignoring zeros.
I just need to understand the concept.
In case of need I could also use NaN instead of zero, but I didn't find e.g. the function
nanlog()
x~=0 returns you the indices of the locations not equal to zero. Then, you can use them to index corresponding locations of x such as follows:
>> x = [1 0 2 3; 0 4 0 5]
x =
1 0 2 3
0 4 0 5
>> mean(x(:)) %#mean of all elements
ans =
1.8750
>> mean(x(x~=0)) %#mean of nonzero elements
ans =
3
>> x(x~=0) = x(x~=0) + 1
x =
2 0 3 4
0 5 0 6
You can use NaN as a temporary and make use of the fact that log(NaN) = NaN, like so:
x(x==0) = NaN;
y = log(x);
y(isnan(y)) = 0;
alternatively, you can use logical indexing:
x(x~=0) = log(x(x~=0));
or, if you want to preserve x,
y = x;
y(y~=0) = log(y(y~=0));
For the example you provide, you can just do
result = nansum(nansum((V.*log(V./(W*H))) - V + W*H));
assuming that V == 0 is the problem.
I create my PN generator with this code:
h=commsrc.pn('GenPoly',gfprimdf(3), 'InitialStates',[1 0 0], ...
'CurrentStates', [1 0 0], 'Mask',[0 0 1], 'NumBitsOut',1)
And this is the GF polynomial of my PN generator:
>> gfpretty(h.GenPoly)
3
1 + X + X
The current states of h is:
>> h.CurrentStates
ans =
1 0 0
looking at the GF polynomial, I think the next statue of h should be [0 1 0]. But Matlab turns the next states of h into [1 1 0] not the expected value [0 1 0].
>> generate(h);
>> h.CurrentStates
ans =
1 1 0
gfprimdf(...) generates the generator polynomial in the order 1+a1*x+a2*x^2+a3*x^3+...+x^N and represents this as a vector
[1 a_1 a_2 ... a_N-1 1]
(ascending order of polynomial powers). However, commsrc.pn expects this vector to be in descending order.
Thus, in your example, the generator polynomial which is really used by commsrc.pn is 1+x^2+x^3, and not 1+x+x^3 as intended. If you instead use
h=commsrc.pn('GenPoly',[1 0 1 1],'InitialStates',[1 0 0],'CurrentStates',[1 0 0],'Mask',[0 0 1],'NumBitsOut',1);
the state after generating one output bit results in the expected state.
I've got a matrix A with the dimensions m X n. For every column i (i > 0and i <= n) I want to flip a coin and fill the whole column with 0 values with probability p. How can this be accomplished in MATLAB?
Example:
A = [1 2 3 4; 5 6 7 8] and p = 0.5 could result in
A' = [1 0 3 0; 5 0 7 0]
You can use the function rand() to generate an array of uniformly distributed random numbers, and use logical indexing to select colums where that array is less than p:
A = [1 2 3 4; 5 6 7 8];
p = 0.5;
A(:, rand(size(A,2), 1)<p) = 0
A =
0 2 0 0
0 6 0 0
You can do something like bsxfun(#times, A, rand(1, size(A, 2)) > p). Alex's answer is admittedly better, though.